曲径通幽论坛

标题: 关于返回对象的总结 [打印本页]

作者: beyes    时间: 2013-10-1 12:06
标题: 关于返回对象的总结
类的成员函数或独立函数都可以返回对象,并有几种返回方式:

1. 返回指向 const 对象的引用


使用 const 引用的常见原因是为了提高效率,比如函数返回传递给它的对象时,返回引用可以提高效率。比如在下面的例子中,使用 Max() 函数返回两个 Vector 对象中较大的一个:
Vector force1(50, 60);
Vector force2(10,70);

Vector max;

max = Max(force1, force2);


下面有 Max() 函数的两种实现:

[C++] 纯文本查看 复制代码
//版本 1
Vector Max(const Vector & v1, const Vector & v2)
{
        if (v1.big() > v2.big())
                return 1;
        else
                return 2;
}

//版本2
const Vector & Max(const Vector &v1, const Vector & v2)
{
        if (v1.big() > v2.big())
                return 1;
        else
                return 2;
}

首先,返回对象时会调用复制构造函数,而返回引用则不会,因此上面代码中的 版本2 要比 版本1所做的工作更少(不需要调用一个函数,也更不需要复制一个临时对象出来),因此效率更高。
其次,传递到 Max() 中的两个对象参数,都被声明为 const 引用,因此返回类型也必须为 const ,这样才匹配。


2. 返回指向非 const 对象的引用


有两种常见的返回非 const 对象的情形,一个是重载赋值运算符,另一个是重载与 cout 一起使用的 << 运算符。前者旨在提高效率,后者则必须这样做。

比如 operator=() 的返回值用于连续赋值:
String s1("Good girl");
String s2, s3;
s3 = s2 = s1;

在上面代码中,s2.operator=() 的返回值被赋给了 s3。这里返回 String 对象 或 String 对象的引用都是可以的,与上述的 Vector 示例的一样,通过使用引用,可避免该函数调用 String 的复制构造函数创建一个新的 String 对象。在这个例子中,返回类型不是 const,因为 operator=() 返回一个指向 s2 的引用,可以对其进行修改,使用 const 就,不行了。

当 operator<<() 的返回值用于串接输出时有:
String s1("Good girl");
cout << s1 << "is coming!";

在上面代码中,operator<<(cout, s1) 的返回值是一个用以显示字符串 "is coming!" 的对象。返回类型必须是 ostream & ,而不能只是 ostream 。如果返回类型是 ostream,那么就需要调用 ostream 类的复制构造函数,但 ostream 没有公有的复制构造函数。幸运的是,返回 cout 的引用是不会带来任何问题的。

3. 返回对象

如果返回的对象是被调用函数中的局部变量,那么就不应按引用方式返回它,因为被调用函数执行完毕时,局部对象会调用析构函数销毁自己。因此,当控制权回到调用函数时,引用的局部对象将不再存在。在这种情况下,应该返回的是对象而不是引用。通常,被重载的算术运算符属于这一类。在这种情况下,就会存在调用复制构造函数来创建被返回对象的开销,但这无法避免。

4. 返回 const 对象
比如我们重载了一个 + 号运算符: Vector::operator+() ,我们一般会如下使用它来相加两个对象:
net = force1 + force2;

然而,也允许像下面奇异的用法:
force1 + force2 = net;
cout << (force1 + force2 = net).magval() << endl;

在实际应用中,谁都不会这么用,但也不能保证百分之百的不被有些人这么写。这种代码之所以可行,是因为复制构造函数将创建一个临时对象来表示返回值,而 net 就被赋给了该临时对象。然而,当临时对象被用完后,就会被丢弃,而 force1, force2, net 这几个对象都会丝毫无损。如果担心这种奇异的行为被滥用,那么有一种简单的解决方案,就是将返回类型声明为 const Vector ,那么 net = force1 + force2; 是合法语句,而 force1 + force2 = net 就是非法的了。


总之,如果方法或函数要返回局部对象,就应返回局部对象,而不是指向对象的引用。在这种情况下,将使用复制构造函数来生成返回的对象。如果方法或函数要返回一个没有公有复制构造函数的类(如 ostream)的对象,它就必须返回一个指向这种对象的引用。最后,有些方法和函数(如重载的赋值运算符)可以返回对象,也可以返回对象的引用,在这种情况下,应首选返回引用,因为其效率更高。





欢迎光临 曲径通幽论坛 (http://www.groad.net/bbs/) Powered by Discuz! X3.2