C++学习之传递和返回对象

当编写成员函数或独立函数返回对象时,通常有这几种选择:返回指向对象的引用、返回指向对象的const引用、返回对象、返回const对象。下面进行讨论。

返回指向const对象的引用

使用const引用的常见原因是提高效率。是因为能返回对象的引用的函数,也可以返回对象来实现。返回对象会导致调用复制构造函数,而返回引用就不会。因此,返回引用做的工作更少,效率更高。

返回指向对象的引用有一个要求,就是指向的对象应该在函数执行期间存在。例如对Vector类编写一个函数Max(),返回两个Vector对象中比较大的一个。则下面两种方法都可行,但第二个版本比较好。

1
2
3
4
5
6
7
Vector Max(const Vector & v1, const Vector & v2)
{
if(v1.magval() > v2.magval())
return v1;
else
return v2;
}

1
2
3
4
5
6
7
8
//better
const Vector & Max(const Vector & v1, const Vector & v2)
{
if(v1.magval() > v2.magval())
return v1;
else
return v2;
}

按值传递or按引用传递?

编写使用对象作为参数的函数时,应按引用而不是按值来传递对象。

原因之一是提高效率,跟返回同样的,如果按值传递对象会涉及到生成临时拷贝、调用复制构造函数、析构函数的步骤,如果按引用传递会使时间的花费少很多。如果函数不修改对象,则应声明参数为const对象引用。

另外一个原因是如果定义为接受基类引用参数的函数,还能接受派生类引用。

返回指向非const对象的引用

两种常见的情形:重载赋值运算符、重载与cout一起使用的<<运算符。前者这样做旨在提高效率,后者则必须这样做。

operator=()的返回值用于连续赋值的话,则返回对象和返回引用都是可行的。但和上面的例子一样,如果返回引用可以免去调用复制构造函数的工作。

operator<<()的返回值用于串接输出,因此返回值必须是一个ostream对象。所以返回值必须是ostream &。如果返回值是ostream,则会要求调用ostream类的复制构造函数,但ostream没有共有的复制构造函数。

返回对象

如果返回的对象是被调用函数中的局部变量,则不应按引用方式返回它,因为被调用函数执行完毕后,局部对象会调用析构函数,控制权回到调用函数时,引用指向的对象将不复存在。通常,被重载的算术运算符属于这种情况。

Vector类加法:

1
2
3
4
5
6
7
8
9
Vector Vector::operator+(const Vector & b)const
{
return Vector(x + b.x, y + b.y);
}

Vector force1(50,60);
Vector force2(10,70);
Vector force3;
force3 = force1 + force2;

这里返回的不是force1force2,因为force1force2在相加的过程中应该本身保持不变,而是返回两个对象的和。函数中应设置一个局部变量来存储计算结果,所以不应该返回指向该临时对象的引用,应该返回对象。

返回const对象

可以把Vector::operator+()的返回类型声明为const Vector。这样可以防止错误的使用。比如下面三条错误的写法:

1
2
3
force1 + force2 = force3;
cout<<(force1 + force2 = force3).magval() << endl;
if(force1 + force2 = force3)

总结:

• 通常,编写使用对象作为参数的函数,应按照引用传递。
• 如果方法或函数需要返回局部对象,则应返回对象
• 如果方法或函数需要返回一个没有公有复制构造函数的类(如ostream),则必须返回指向对象的引用
• 有些方法和函数既可以返回对象,也可以返回引用,则出于效率方面的考虑应首选返回引用。