5.6 C++重载下标操作符
参考:http://www.weixueyuan.net/view/6384.html
总结:
下标操作符是必须要以类的成员函数的形式进行重载的。其在类中的声明格式如下:
返回类型 & operator[] (参数)
或
const 返回类型 & operator[] (参数) const , 后面的 const可使两函数是不同的函数,编译器可以分辨出来。
如果使用第一种声明方式,操作符重载函数不仅可以访问对象,同时还可以修改对象。如果使用第二种声明方式,则操作符重载函数只能访问而不能修改对象。如语句“arr[5] = 7;”语句是无效的,
非const成员函数不能处理const对象,这也是第二种的应用场景之一。
---------------------------
在前面已经提到下标操作符是必须要以类的成员函数的形式进行重载的。其在类中的声明格式如下:
返回类型 & operator[] (参数)
或
const 返回类型 & operator[] (参数)
如果使用第一种声明方式,操作符重载函数不仅可以访问对象,同时还可以修改对象。如果使用第二种声明方式,则操作符重载函数只能访问而不能修改对象。
在我们访问数组时,通过下标去访问数组中的元素并不具有检查边界溢出功能,我们可以重载下标操作符使之具有相应的功能。
例1:
#include<iostream> #include<string> using namespace std; class Array { public: Array(){length = 0; num = NULL;}; Array(int n); int & operator[]( int ); const int & operator[]( int )const; int getlength() const {return length;} private: int length; int * num; }; Array::Array(int n) { try { num = new int[n]; } catch(bad_alloc) { cerr<<"allocate storage failure!"<<endl; throw; } length = n; } int& Array::operator[](int i) { if(i < 0 || i >= length) throw string("out of bounds"); return num[i]; } const int & Array::operator[](int i) const { if(i < 0 || i >= length) throw string("out of bounds"); return num[i]; } int main() { Array A(5); int i; try { for(i = 0; i < A.getlength(); i++) A[i] = i; for(i = 0 ;i < 6; i++ ) cout<< A[i] <<endl; } catch(string s) { cerr<< s <<", i = "<< i <<endl; } return 0; }
本例中定义了一个Array类,表示的是一个整形数组,在类中我们重载了下标操作符,使之具备检测下标溢出的功能。在类中为了方便我们使用了string类,这个类将在后面会进行详细介绍,在这里可以将其对象理解为一个字符串。在本例中重载下标操作符,我们提供了两个版本的重载下标操作符函数:
int & operator[]( int );
const int & operator[]( int )const;
需要注意的是第一个下标操作符重载函数最后面不带有const,加上const意味着该成员函数是常成员函数,如果第一个函数后面也加上了const,则两个函数仅有返回值不相同,这个不足以用于区分函数,编译器会提示语法错误。这两种版本的下标操作符重载函数其实很好理解,一个是可以修改类对象,下面一个则只可以访问对象而不能修改对象。对于上面一种下标操作符重载函数的声明,以下两个语句都是有效的:
arr[5] = 7;
int var = arr[3];
换言之,我们既可以访问类对象,同时又能修改类对象。“arr[5]”其实可以理解为:
arr.operator[]( 5 )
而对于下面一种下标操作符重载函数,我们不能修改对象,也就是说语句“arr[5] = 7;”语句是无效的,但是它依然可以用于访问对象,因此“int var = arr[3];”语句仍然有效。
我们再来看一下下标操作符重载函数的定义,在函数体内部,先进行下标越界检测,如果出现越界则抛出异常,否则就返回下标 i 所对应的数据。这两种版本的下标操作符重载函数的函数定义都是如此。
我们来看一下程序输出结果:
0
1
2
3
4
out of bounds, i = 5
在例1中即使我们没有定义const版本的,上面的例子也是可以正确运行的,但是非const成员函数不能处理const对象,因此通常我们在设计程序时,会同时提供两种版本的操作符重载函数。在例1中如果我们增添下面一个display顶层函数,用于打印对象数组中的所有元素。
void display(const Array & A) { for(int i=0; i < A.getlength(); i++) cout<< A[i] <<endl; }
此时如果我们在例1中没有定义const版本的下标操作符重载函数,则例1将会出现语法错误而无法编译通过的。