======================================================
大家请把我的文章当参考,详细内容 还请参照 权威书籍
<c++ programming language>如果文中有错误和遗漏,
请指出,Aear会尽力更正, 谢谢!
======================================================
废话不多说,这次讲的是 Operator overload. 关于operator, 在 < The C++ Programing Language > 里的描述,可以用做overload的如下:
+ * / % ^ & | ~ ! = < > += = *= /= %= ^= &= |= << >> >>= <<= == != <=
>= && || ++ >* , > [] () new new[] delete delete[]
先从 operator = 说起。上章中Aear已经提到过,这里再次强调下,只要是在class member中有 pointer的存在,class 就应该提供 copy constructor 和 operator =.
除了 operator =以外,最常用的operator就是 + - * / += -+ *= /= ++ --。 由于四则运算大同小异,我们就拿简单的 + 来举例子说明。让我们看下下面的这段代码有什么问题:
class Test {
private:
int internalData;
public:
// constructor and destructor
Test(int data = 0) : internalData(data) {};
Test(const Test & Para) : internalData(Para.internalData) {};
~Test() {};
// Operator overlording
Test & operator += (const Test & Para1);
Test operator + (const Test & Para1);
};
Test & Test::operator += ( const Test & Para1 )
{
internalData += Para1.internalData;
return * this;
}
Test Test::operator + (const Test & Para1)
{
Test result;
result.internalData = internalData + Para1.internalData;
return result;
}
首先让我们比较一下 += 和 + 两个operator的效率,我们可以看到,在"+="中,返回的是 *this的reference,而在+中,返回的是一个临时创建的 result,并且 result object在返回的过程中,由于是return by value,因此compiler会掉用copy constructor把result拷贝到返回值中,然后掉用 result.~test()销毁掉这个临时变量。也就是说,使用 + 比 += 要产生更多的overhead。在某些效率第一的情况下,临时变量的constructor和destructor都是非常昂贵的操作。比如:
=============one temporary object=============
Test x1 = x2 + x3;
为了提高效率,我们可以这么写:
=============no temporary object=============
Test x1(x2);
x1 += x3;
简单一点的表达式有可能会被compiler优化掉,但是复杂的表达式,只能才用手动的形式优化。
让我们再仔细的看下 Test Test::operator + (const Test & Para1) 这个函数。如果考虑程序的具体实现,我们可以看出来 operator += 和 operator +没有本质的却别,但是如果我们需要改动 Test + 的操作,就必须同时更改 operator += 和 operator + 实现,对同一种功能在几处不同的地方进行维护,并不是良好的设计,因此,我们应该对 Test Test::operator + (const Test & Para1) 做如下改动,使得程序更加容易维护:
=============easy to maintain=============
Test Test::operator + (const Test & Para1)
{
Test result(*this);
result += Para1;
return result;
}
可以看到在operator +里调用了 +=的操作,因此,如果我们需要给加法赋予不同的含义,只需要更改 operator += 就足够了。
让我们继续深入的看 Test Test::operator + (const Test & Para1)。值得强调的是,无论如何temporary object是必须存在的,无数大师的经验证明,想用static member, dynamic memory等方法消除掉 temporary object 的 construction 和 destruction,都会产生这样或者那样的逻辑和程序错误。
但是我们仍然可以利用compiler来对这个temporary object进行优化。对于Test Test::operator + (const Test & Para1) 这样的操作,compiler会传递给 operator + 一个 temporary object, 如果 operator +里的代码合适,那么compiler就会用这个temporary object 代替程序里创建的temporary object,从而减少了constructor和destructor的掉用。经过compiler优化后的pseudocode如下:
Test::operator + (Test & Temporary, const Test & Para1)
{
Temporary.internalData = internalData + Para1.internalData;
return;
}
这样减少了temporary object 的construction 和 destruction,效率就会提高很多,但是要想使compiler能够进行 return by value的优化,必须满足2个条件:
1. class 必须有 copy constructor
2. 在代码中明确表示,返回的是个temporary object.
因此,出了提供copy constructor外,还必须对 operator + 进行适当的修改,最终代码如下:
==========Final Version for Maintenance and Optimization==========
Test Test::operator + (const Test & Para1)
{
return Test(*this) += Para1;
}
在这个代码里边,最明显的区别就是没有result这个变量,而是返回一个临时创建的Test object,因此compiler就会知道这个函数可以用临时变量优化。
也许你会感到惊讶,不过这个operator +还不是最快速的。因为我们看到,在Test(*this) += Para1 的过程中,调用了一次constructor 一次 operator +=,但是已经足够了。不过为了效率,我们有更加极端的方法,在如下的代码中,我们舍弃了可读性,可维护性等等,只为了更快的速度:
==========糟糕的风格,不过更快==========
class Test {
...
private:
// cosntructor for operator +
Test(int data, const Test & Para1 ) : internalData(data + Para1.internalData) {};
};
Test Test::operator + (const Test & Para1)
{
return Test(internalData, Para1);
}
如果同时还要定义 operator - * /等操作的constructor,我们可以适当更改constructor的signature,从而可以用constructor实现不同的运算
关于operator第一部分今天就说这么多,大家有空去坐坐 http://blog.sina.com.cn/u/1261532101 ;下次见。