1.重载的限制:
1)重载后的操作符必须至少有一个操作数是用户自定义的类型,这可以防止用户把标准操作符给重载。
比如 T operator-(double a,double b)//ERROR
2)不能违反原来操作符的句法规则。
3)不能定义新的操作符,否则那就不叫重载了。
4)不能重载下面的操作符;
sizeof
.
.*
::
?:
typeid
const_cast
dynamic_cast
reinterpret_cast
static_cast
除上面的操作符外,其他的都可以被重载。
5)调用重载函数时,左侧的操作数是调用对象,比如:
A = B*2.75 将会被编译器转化为下面重载函数的调用
A = B.operator * (2.75)
2.重载操作符与友元
为什么需要友元?在类重载二元操作符时常需要友元。比如还是上面A=B*2.75的例子,乘法交换两个操作数是非常正常的,即B*2.75与2.75*B应该是等价的,而按照重载操作符的规则,左侧的操作数是调用对象,但2.75显然不是,因此当你写2.75*B时,编译器就不知道怎么办了。解决办法是你可以定义下面的非成员函数:
T operator* (double a,T b)
其实现可能是:
{
T c;
c.t = a*b.t;
return c;
}
但这样还不行,因为a无法访问T的私有成员,即a* b.t 是非法的。这时候就需要用到友元了。
friend T operator * (double a,T b);
关于友元函数需要记住两点:
1.虽然友元函数在类声明中声明,但是它不是成员函数,因此不能使用成员操作符来调用。
2.友元函数虽然不是成员函数,但是与成员函数的访问权限相同。
如果要为类重载操作符,并将非类的项作为第一个操作数,则可以使用友元函数来反转操作数的顺序。
最常见的友元函数:重载<<操作符
我们早已经习惯了这样的输出语句:
int i=2; cout << "i="<<i<<endl; double d = 2.1; cout <<"d="<<d<<endl;
cout是ostream的对象,ostream对<<操作符进行了重载,它能够识别所有的c++基本类型,因为对于每种基本类型,ostream都包含其对应的operator<<()的定义,因此我们可以放心地进行语句输出。那如果我们期望用户自定义类型(比如自定义类型 T),我们也期望能够count<<"t="<<t<<endl;(t是T的一个实例),该怎么办?
首先需要在T中重载<<,但这样的话,T将作为第一个操作数,所以就要这样输出T: t << out; 非常怪异。使用有元函数就可以解决这个问题:
friend ostream& operator<<(ostream& os,const T& t); ostream& operator<<(ostream& os,const T& t) { os <<"t="<<t.abc<<endl; return os; }