c++很好的一个优点就是根据用户定义的类,操作符有不同的意义。这就叫operator overloading. 一般通过在类中提供一个特别的成员函数来实现。可以被overloading的操作符有以下几种:
= (assignment operator)
+ - * (binary arithmetic operators)
+= -= *= (compound assignment operators)
== != (comparison operators)
对assignment operator(=), 一些最基本的guidelines很重要。
一个典型的=overloading实现如下:
class Myclass{
public:
Myclass & operator= (const Myclass &opb);
..
}
Myclass a,b;
b = a; //same as a.operator(a);
注意=操作符中,右边的操作数是个常引用(const-reference)。原因是我们不希望改变右边的值,我们只想将右边的值给左边。
另外,返回值是个引用,这主要是为了实现链式操作(operator chaining):
int a,b,c,d,e;
a = b = c = d = e = 520;
编译器解释为:
a=(b=(c=(d=(e=520))));
即e=520首先执行,然后返回e作为结果。e的值再给d….。为了实现这个,赋予值操作必须返回一个值。应该返回的值是操作符左边的一个引用。
另外,我们并没有指定返回值是一个常引用。因为这样允许写以下代码:
(a = b) = c;
粗一看,你可能觉得应该设定返回一个常引用来避免这种情况。但statements like this will work with primitive types。更糟糕是是有些编译工具依赖此行为。因此返回一个非常引用是非常重要的事情。
// Take a const-reference to the right-hand side of the assignment.
// Return a non-const reference to the left-hand side.
MyClass& MyClass::operator= (const MyClass &rhs) {
... // Do the assignment operation!
return *this; // Return a reference to myself.
}
注意this 是一个指针,他指向成员函数正在被调用的对象。由于a=b被处理为
a.operator(b). 对象a 的成员函数被调用。
但是,这个成员函数要返回一个指向对象的引用。而不是一个指向对象的指针。因此返回*this, 它返回的是this指向的东西,而不是指针本身。
最后一件重要事情是检查自赋值操作。当自定义类有分配内存操作时,这一点非常重要。看以下例子:
MyClass& MyClass::operator=(const MyClass &rhs) {
// 1. Deallocate any memory that MyClass is using internally
// 2. Allocate some memory to hold the contents of rhs
// 3. Copy the values from rhs into this instance
// 4. Return *this
}
以下调用:
MyClass mc;
mc = mc;
因为mc同时在左手边和右手边,第一件事情发生的是mc将释放它保持的任何内存。但是,这个内存也是拷贝操作需要用的内存,因为mc也在右手边。因此操作完全混乱。
最容易的是进行自调用检查,对此问题有很多解。在此采用比较地址方法,如果两个地址相同,则认为是同样的,不进行赋值操作。如果不同,继续。
因此,正确和安全的版本是:
MyClass& MyClass::operator=(const MyClass &rhs) {
// Only do assignment if RHS is a different object from this.
if (this != &rhs) {
... // Deallocate, allocate new space, copy values...
}
return *this;
}
**总结:
1) 右手边是常引用;
2) 返回是左边非常引用;
3) 比较指针避免自赋值。**