C++运算符重载(五)
2016-12-12 12:12
190 查看
C++允许在自己的类中,或是在全局作用域中重定义运算符的含义。由于很多面向对象的语言没有提供这种能力,因此你可能会低估这种特性在C++中的作用。C++中运算符的概念十分广泛,甚至包含[](数组索引)、()(函数调用)、类型转换以及内存分配和释放例程。可以通过运算符重载来改变语言运算符对自定义类的行为。能让自己的类具有内建类型的类似行为,甚至可以编写看上去类似于数组、函数或指针的类。在博主的《C++运算符重载》系列博文中会对我们常用的运算符提供重载的实例,希望大家能有所收获。额,本篇博文就让我们一起来探讨一下重载运算符中的下标访问运算符重载吧。
一说到下标访问就很容易让人联想到数组,我们可以通过下标很方便的访问数组中的任意合法元素。博主在这里先暂时假设你从来没有听说过STL,更不知道vector和array类模板。博主将在这里封装一个简单的动态数组类模板,这个类允许设置和获取指定索引位置的元素,并会自动完成所有的内存分配操作。废话就不多说了,咱们直接上代码吧。当然,如果你是高手就可以略过啦^^。
//MyArray.h
#pragma
once
#include
<iostream>
using
namespacestd;
template <typenameT>
class
MyArray
{
public:
MyArray(size_t size/* = 0*/);
virtual~MyArray();
//禁用拷贝构造函数和复制赋值运算符
MyArray(constMyArray<T>&rhs) =
delete;
MyArray<T>&operator = (const
MyArray<T> &rhs) =
delete;
//禁用自增和自减运算符(由于数组名是常量,不能修改)
MyArray<T>&operator ++ () =
delete;
MyArray<T>&operator -- () =
delete;
MyArray<T>operator ++ (int) =
delete;
MyArray<T>operator -- (int) =
delete;
//重载下标访问运算符
T& operator [] (size_tindex);
constT& operator [] (size_tindex)
const;
//重载“+”运算符,方便通过数组名访问数组中所有元素
T* operator + (rsize_tindex);
constT* operator + (rsize_tindex)
const;
//重载解除引用运算符,以便通过数组名访问数组中的第一个元素
T operator * ();
constT operator * ()
const;
//获取数组尺寸
rsize_t getSize() const;
//输出数组中所有元素值
voidshow() const;
private:
//当数组空间不够时,为数组再开辟一块更大的空间
voidresize(size_t size);
//初始化数组中每个元素
voidinitElements();
private:
T *m_elements;//数组裸指针
size_t m_size;//数组尺寸
};
//包含模板实现部分
//如果"MyArray.inl"是头文件就直接包含就行
//如果"MyArray.inl"是源文件,则必须将其从项目中移除
#include
"MyArray.inl"
//MyArray.inl
template <typenameT>
MyArray<T>::MyArray(size_t
size/* = 0*/)
{
if(size<= 0)
{
m_size= 0;
m_elements=
nullptr;
return;
}
m_size =
size;
m_elements=
new T[m_size];
initElements();
}
template <typenameT>
MyArray<T>::~MyArray()
{
if(nullptr!= m_elements)
{
delete[]m_elements;
m_elements=
nullptr;
m_size= 0;
}
}
template <typenameT>
T&
MyArray<T>::operator [] (size_tindex)
{
size_t size = 0;
if(index>= m_size)
{
if(2*m_size > index)
{
size= 2 * m_size;
}
else
{
size=
index + 1;
}
resize(size);
}
returnm_elements[index];
}
template <typenameT>
const
T&MyArray<T>::operator[] (size_t
index)const
{
if(index>= m_size)
{
throwstd::out_of_range("数组访问越界!");
}
returnm_elements[index];
}
template <typenameT>
void
MyArray<T>::resize(size_tsize)
{
//将原数组的内存和尺寸保存起来
T *oldElements = m_elements;
size_t oldSize = m_size;
//分配新内存
m_size =
size;
m_elements=
new T[m_size];
//初始化新分配的内存空间
initElements();
//拷贝
for(size_t i = 0; i < oldSize; ++i)
{
m_elements[i]= oldElements[i];
}
//释放原数组内存空间
delete[]oldElements;
oldElements=
nullptr;
}
template <typenameT>
void
MyArray<T>::initElements()
{
for(size_t i = 0; i < m_size; ++i)
{
m_elements[i]=
T();
}
}
template <typenameT>
rsize_t
MyArray<T>::getSize()
const
{
returnm_size;
}
template <typenameT>
T*
MyArray<T>::operator + (rsize_tindex)
{
if(index>= m_size)
{
throwstd::out_of_range("数组访问越界!");
}
return(m_elements + index);
}
template <typenameT>
const
T*MyArray<T>::operator+ (rsize_t
index)const
{
if(index>= m_size)
{
throwstd::out_of_range("数组访问越界!");
}
return(m_elements + index);
}
template <typenameT>
void
MyArray<T>::show()
const
{
cout<<
"{";
for(size_t i = 0; i < m_size; ++i)
{
cout<< m_elements[i] <<
", ";
}
cout<<
"}" << endl;
}
template <typenameT>
T
MyArray<T>::operator * ()
{
return*(operator + (0));
}
template <typenameT>
const
TMyArray<T>::operator* ()
const
{
return*(operator + (0));
}
//main.cpp
#include
"MyArray.h"
int main(int argc,char **argv)
{
cout<<
"into main"<< endl;
try
{
//使用自定义数组类定义一个有10个int型元素的数组
MyArray<int>nArray(10);
//通过下标访问运算符给数组每个元素进行初始化
for(size_t i = 0; i < nArray.getSize(); ++i)
{
nArray[i]= i;
}
//输出数组中每个元素
cout<<
"nArray = ";
nArray.show();
//通过operator +
返回数组中元素的地址
//再通过返回的地址访问元素存储空间
cout<< *(nArray + 3) << endl;
*(nArray+ 2) = 7;
//输出数组中每个元素
cout<<
"nArray = ";
nArray.show();
//越界访问数组元素,将抛出数组访问越界异常
//cout<< *(nArray + 10) << endl;
//当数组空间不够时,重新开辟一块新的空间
cout<<
"size = "<< nArray.getSize() << endl;
nArray[10]= 80;
cout<<
"size = "<< nArray.getSize() << endl;
//由于数组名是常量,不可以修改,否则编译器会报错。
//cout<< (++nArray) << endl;
//数组名是数组第一个元素的地址
cout<<
"*nArray = "<< *nArray << endl;
nArray.show();
}
catch(conststd::out_of_range &e)
{
cout<<
"in main caught a exception: "<< e.what() << endl;
}
cout<<
"out of main"<< endl;
return0;
}
程序运行结果:
怎么样,封装一个简单的动态数组也就这么easy!如果想加深对运算符重载的理解,就得多编写类型的程序,尝试着去封装一些类模板,练着练着你的境界就不一样啦。通过博主封装的MyArray类模板实例的学习,相信大家已经对下标访问运算符重载掌握的差不多了。如果你还没有搞清楚这个实例,那么就得加把劲了。你可以编写一些简单的实例,去尝试着运用它们,就算错了也是一种收获。
C++运算符重载中的算术运算符重载就讲到这里,相信大家对它的概念和用法都已经熟悉了吧。如果想了解更多关于C++运算符重载的知识,请关注博主的《C++运算符重载》系列博文,在那里我们将会通过程序实例去探讨C++运算符重载的魅力,相信你在那里会有不一样的收获。当然,如果你对C++很感兴趣的话,那么请关注博主的《漫谈继承技术》和《灵活而奇特的C++语言特性》系列博文,在那里你也许会发现C++更大的魅力,让你对这门博大精深的语言更加爱不释手。
一说到下标访问就很容易让人联想到数组,我们可以通过下标很方便的访问数组中的任意合法元素。博主在这里先暂时假设你从来没有听说过STL,更不知道vector和array类模板。博主将在这里封装一个简单的动态数组类模板,这个类允许设置和获取指定索引位置的元素,并会自动完成所有的内存分配操作。废话就不多说了,咱们直接上代码吧。当然,如果你是高手就可以略过啦^^。
//MyArray.h
#pragma
once
#include
<iostream>
using
namespacestd;
template <typenameT>
class
MyArray
{
public:
MyArray(size_t size/* = 0*/);
virtual~MyArray();
//禁用拷贝构造函数和复制赋值运算符
MyArray(constMyArray<T>&rhs) =
delete;
MyArray<T>&operator = (const
MyArray<T> &rhs) =
delete;
//禁用自增和自减运算符(由于数组名是常量,不能修改)
MyArray<T>&operator ++ () =
delete;
MyArray<T>&operator -- () =
delete;
MyArray<T>operator ++ (int) =
delete;
MyArray<T>operator -- (int) =
delete;
//重载下标访问运算符
T& operator [] (size_tindex);
constT& operator [] (size_tindex)
const;
//重载“+”运算符,方便通过数组名访问数组中所有元素
T* operator + (rsize_tindex);
constT* operator + (rsize_tindex)
const;
//重载解除引用运算符,以便通过数组名访问数组中的第一个元素
T operator * ();
constT operator * ()
const;
//获取数组尺寸
rsize_t getSize() const;
//输出数组中所有元素值
voidshow() const;
private:
//当数组空间不够时,为数组再开辟一块更大的空间
voidresize(size_t size);
//初始化数组中每个元素
voidinitElements();
private:
T *m_elements;//数组裸指针
size_t m_size;//数组尺寸
};
//包含模板实现部分
//如果"MyArray.inl"是头文件就直接包含就行
//如果"MyArray.inl"是源文件,则必须将其从项目中移除
#include
"MyArray.inl"
//MyArray.inl
template <typenameT>
MyArray<T>::MyArray(size_t
size/* = 0*/)
{
if(size<= 0)
{
m_size= 0;
m_elements=
nullptr;
return;
}
m_size =
size;
m_elements=
new T[m_size];
initElements();
}
template <typenameT>
MyArray<T>::~MyArray()
{
if(nullptr!= m_elements)
{
delete[]m_elements;
m_elements=
nullptr;
m_size= 0;
}
}
template <typenameT>
T&
MyArray<T>::operator [] (size_tindex)
{
size_t size = 0;
if(index>= m_size)
{
if(2*m_size > index)
{
size= 2 * m_size;
}
else
{
size=
index + 1;
}
resize(size);
}
returnm_elements[index];
}
template <typenameT>
const
T&MyArray<T>::operator[] (size_t
index)const
{
if(index>= m_size)
{
throwstd::out_of_range("数组访问越界!");
}
returnm_elements[index];
}
template <typenameT>
void
MyArray<T>::resize(size_tsize)
{
//将原数组的内存和尺寸保存起来
T *oldElements = m_elements;
size_t oldSize = m_size;
//分配新内存
m_size =
size;
m_elements=
new T[m_size];
//初始化新分配的内存空间
initElements();
//拷贝
for(size_t i = 0; i < oldSize; ++i)
{
m_elements[i]= oldElements[i];
}
//释放原数组内存空间
delete[]oldElements;
oldElements=
nullptr;
}
template <typenameT>
void
MyArray<T>::initElements()
{
for(size_t i = 0; i < m_size; ++i)
{
m_elements[i]=
T();
}
}
template <typenameT>
rsize_t
MyArray<T>::getSize()
const
{
returnm_size;
}
template <typenameT>
T*
MyArray<T>::operator + (rsize_tindex)
{
if(index>= m_size)
{
throwstd::out_of_range("数组访问越界!");
}
return(m_elements + index);
}
template <typenameT>
const
T*MyArray<T>::operator+ (rsize_t
index)const
{
if(index>= m_size)
{
throwstd::out_of_range("数组访问越界!");
}
return(m_elements + index);
}
template <typenameT>
void
MyArray<T>::show()
const
{
cout<<
"{";
for(size_t i = 0; i < m_size; ++i)
{
cout<< m_elements[i] <<
", ";
}
cout<<
"}" << endl;
}
template <typenameT>
T
MyArray<T>::operator * ()
{
return*(operator + (0));
}
template <typenameT>
const
TMyArray<T>::operator* ()
const
{
return*(operator + (0));
}
//main.cpp
#include
"MyArray.h"
int main(int argc,char **argv)
{
cout<<
"into main"<< endl;
try
{
//使用自定义数组类定义一个有10个int型元素的数组
MyArray<int>nArray(10);
//通过下标访问运算符给数组每个元素进行初始化
for(size_t i = 0; i < nArray.getSize(); ++i)
{
nArray[i]= i;
}
//输出数组中每个元素
cout<<
"nArray = ";
nArray.show();
//通过operator +
返回数组中元素的地址
//再通过返回的地址访问元素存储空间
cout<< *(nArray + 3) << endl;
*(nArray+ 2) = 7;
//输出数组中每个元素
cout<<
"nArray = ";
nArray.show();
//越界访问数组元素,将抛出数组访问越界异常
//cout<< *(nArray + 10) << endl;
//当数组空间不够时,重新开辟一块新的空间
cout<<
"size = "<< nArray.getSize() << endl;
nArray[10]= 80;
cout<<
"size = "<< nArray.getSize() << endl;
//由于数组名是常量,不可以修改,否则编译器会报错。
//cout<< (++nArray) << endl;
//数组名是数组第一个元素的地址
cout<<
"*nArray = "<< *nArray << endl;
nArray.show();
}
catch(conststd::out_of_range &e)
{
cout<<
"in main caught a exception: "<< e.what() << endl;
}
cout<<
"out of main"<< endl;
return0;
}
程序运行结果:
怎么样,封装一个简单的动态数组也就这么easy!如果想加深对运算符重载的理解,就得多编写类型的程序,尝试着去封装一些类模板,练着练着你的境界就不一样啦。通过博主封装的MyArray类模板实例的学习,相信大家已经对下标访问运算符重载掌握的差不多了。如果你还没有搞清楚这个实例,那么就得加把劲了。你可以编写一些简单的实例,去尝试着运用它们,就算错了也是一种收获。
C++运算符重载中的算术运算符重载就讲到这里,相信大家对它的概念和用法都已经熟悉了吧。如果想了解更多关于C++运算符重载的知识,请关注博主的《C++运算符重载》系列博文,在那里我们将会通过程序实例去探讨C++运算符重载的魅力,相信你在那里会有不一样的收获。当然,如果你对C++很感兴趣的话,那么请关注博主的《漫谈继承技术》和《灵活而奇特的C++语言特性》系列博文,在那里你也许会发现C++更大的魅力,让你对这门博大精深的语言更加爱不释手。
相关文章推荐
- C++运算符重载经典案例
- C++运算符重载
- C++运算符重载(12) - 重载数组索引操作符[]
- C++运算符重载代码分析
- C++运算符重载小程序
- C++运算符重载(operator)
- c++运算符重载
- 关于c++运算符重载 + 和 ++ 运算符 【2013.10.18】
- C++运算符重载例子代码
- c++运算符重载总结
- [置顶] # c++运算符重载之 前置++, 后置++, 负号运算符, 类型转换函数, 以及输入输出运算符
- C++运算符重载(转载)
- C++运算符重载(8) - 默认赋值操作符和引用
- C++运算符及其重载问题
- C++运算符重载(成员函数方式)
- c++运算符重载,输出符 4000 号重载
- C++运算符重载
- C++运算符重载的方法
- C++运算符重载的方法详细解析
- c++运算符重载---20