C++运算符重载函数可以是类的成员函数也可以是全局函数。
对于-> ,[ ]和()以及赋值运算符必须重载为类的成员函数。
对于二元运算符来说,如果左操作数不是该类的对象的话,那么该运算符重载函数不能作为类的成员函数,比如流插入运算符<<和流提取运算符>> ,它们必须作为全局函数。
当运算符函数是类的成员函数时,该运算符的左操作数必须是该类的对象。若左操作数是不同类的对象或者基本类型对象,那么该运算符函数必须作为全局函数来实现。如果该运算符函数会访问类的private或者protected成员,那么请把它设为该类的友元函数。
重载的++运算符:
①前置++
一个类的前置++运算符应该返回该类对象的一个引用,以便返回的值可以作为左值继续对其赋值。
类& operator++();
②后置++
后置++运算符应该返回该类的对象,因为在进行自增前,后置操作先返回一个包含对象原始值的临时对象,临时对象只能作为右值,不能作为左值出现在赋值运算符=的左侧。
为了让编译器区分出前置++与后置++,后置++的函数原型如下:
类 operator++(int a);
调用的时候编译器自动会调用operator++(0),int a纯粹是个哑值,没任何作用,只是为了让编译器区分前置++与后置++。
重载的->运算符:
箭头操作符接受一个对象和其成员名,看起来它就像个二元操作符。但是不管外表看起来如何,箭头操作符不接受显式形参。
没有第二个形参是因为->的右操作数是类成员的一个标识符,没有明显可行的途径将一个标识符作为形参传递给函数。
定义两个类如下:
class Element
{
public:
action();
private:
int val;
};
class Test
{
public:
Element* operator->()
{return &data;}
private:
Element data;
};
Element* a;
a->action();
Test t;
t->action();
由于优先级的原因,实际上等价于
(a->action)();
即编译器先对a->action求值,求值完后再调用求值结果。
编译器对a->action进行求值:如果
(1) a是指向含有action成员的类的对象的一个指针,那么编译器将该代码编译为调用该对象的action成员;
(2) a是定义了operator->()操作符的类的一个对象,则a->action就被编译成(a.operator->())->action。即执行a的operator->()函数,设执行后返回的结果为result,那么该语句就变成了result->action,则编译器继续编译result->action,重复进行上述过程的判断...
(3) 除上述两种情况外,其他情况都会报错。
operator->()函数的返回类型:
要么返回指向类类型的指针,要么就返回包含箭头操作符重载函数的类的对象或其引用。
对于后一种情况,将递归应用该操作符,即编译器将检查返回的对象所属的类中是否包含了operator->()函数,如果有,则就继续调用该operator->()函数。这个过程会一直进行下去,直至返回一个含有->右端指定成员的类对象的指针。