一、 函数返回值
说到operator=的返回值,那么先必须要说一下函数的返回值。函数的返回值用于初始化在调用函数处创建的临时对象,函数的返回值分值类型和引用类型。
1、 返回值类型
返回值类型, 即告诉编译器在调用函数处创建的临时对象是函数返回对象的一个值类型。
Test Fun() {
Test a;
return a;
}
Test b = Fun();
则经过编译器处理后伪代码大致如下:
Fun()里return a;调用拷贝构造生成一个临时Test对象termporary;
Test b = termporary; ------这里再用termporary通过拷贝构造来初始化a
termporary.~Test();---------释放掉此临时对象或者经过编译器优化为:
Test b = Fun(); -------这里Fun里return a的时候没有生成一个临时的Test对象,而是直接通过拷贝构造函数将a初始化对象实例b。
如果只是单纯调用Fun()函数,如:
Fun();
则return a;的时候会调用拷贝构造函数生成一个临时Test对象,函数调用结束就会掉此临时对象的析构函数将它释放掉。
2、返回引用类型
返回引用类型, 即告诉编译器在调用函数处创建的临时对象是函数返回对象的一个引用。
Test& Fun() {
static Test a;
return a;
}
Test b = Fun();
则经过编译器处理后伪代码大致如下:
Test b = termporary; ------这里再用termporary通过拷贝构造来初始化b
但是如果通过形如Test& a = Fun();来调用函数呢?经过编译器处理后伪代码大致如下:
Fun(); -------return a;的时候创建Fun的返回对象实例a的引用termporary,即Test& termporary = a;
Test &b = termporary; ------b为termporary的引用,即为Fun的返回对象实例a的别名
注:
函数返回引用类型,其实就是返回了一个真实对象的一个别名(返回的对象termporary就是真实对象的一个别名)
二、operator=返回值
<<Effective C++>>中说到 operator=必须要返回一个reference to *this,为什么呢? 他给出的理由是 Test a, b, c; a = b = c; 为了实现这种“连锁赋值”。 那么真的如书上所说的如果不返回引用类型就无法实现上述“连锁赋值”吗? 其实不然。
class Test
{
public:
Test() { };
Test(int i) { number = i; };
~Test( ) { };
Test(const Test& p){ number = p.number; };
Test operator=(const Test& p) {number = p.number; return *this;};
public:
void DoSomething() {cout << "My test" << endl; };
public:
int number;
};
如上代码,Test 的operator=返回的不是引用类型,但是照样能实现a = b = c;这种“连锁赋值”。只是比operator=返回的是引用类型情况下多调用两次copy构造函数。 a = b = c;被解析为 a = (b = c), 那么b = c时返回值必须通过copy构造函数来初始化临时对象termporary。 然后termporary通过操作符号operator=赋值给a,即a = termporary, operator=返回时同样会调用copy构造函数来初始化另外一个临时对象。故多调用两次copy构造函数而已。
所以,只是说从效率上来说, operator=返回引用比返回值类型要高效。
另外, 如果想要支持另外一种“连锁赋值”,如 (a = b) = c; 那么就必须要operator=返回引用类型。即 a = b 返回的是 a的一个引用类型临时对象termporary,那么将c赋值给这个a的引用,即可正确地实现表达式的含义。 如果operator=返回值类型呢? 那么a = b 返回的是a的一个值类型临时对象termporary, 那么c赋值给这个临时对象termporary后,根本没有改变a的值,也就没有正确地实现表达式的含义。
所以,综上两点, operator=还是老老实实地返回一个reference to *this吧。