qscool1987 2014年05月07日
函数返回值类型为值类型,非常引用类型和常引用类型
函数返回值类型为值类型,非常引用类型和常引用类型
首先为何要为引用类型?C++中的引用引入主要是为了效率,防止大对象的拷贝问题,这就引发两个问题,是使用源对象还是,源对象的副本问题。以及是否修改这个源对象的问题
函数返回值为非常引用类型,那么这个函数调用表达式可以做左值,就能够用于需要左值的地方,如 = 操作符的左操作数,以及用于++,---操作符,在需要右值表达式的地方,会进行左值到右值的转换,所以也同样可以

基于函数,讨论非成员函数和成员函数两种问题
1.非成员函数返回非常引用类型问题
如 class A{};
A& fun(){return A();}
像这样的问题,标准明确说明为未定义行为,既然为未定义行为就不予讨论

A& fun(A &a){//对a做处理; return a;}
像这样的问题,根可以不需要有返回值
定义为 void fun(A &a){//对a做处理; }
调用完后,继续对a进行操作是同样可以完成目的的
通过上述两种情况发现,对于非成员函数,返回值为非常引用类型总是存在一些问题,或者可以避免,
如果这样调用
A ma = fun(a);
fun(a)是一个左值,同时是一个对象表达式,做了右值,会调用拷贝构造函数
如果这样调用
A &ma = fun(a);
fun(a)是一个左值,同时是一个对象表达式,ma绑定这个对象

2.非成员函数返回常引用类型问题
const A& fun(A &a){//对a做处理; return a;}
这样就有意思了,对于这样的函数调用
A a;
const A &ma = fun(a);
表达式fun(a)是一个常量表达式
ma和a具有相同的对象值描述,ma不可以修改其类容,而a可以修改
也许这样的形式有存在的必要吧!

3:成员函数返回值为非常引用类型
class B{};

class A
{
public:
B& getB(){ return b; }
private:
B b;
};

A a;
B &bb = a.getB();
上述测试代码做到了避免拷贝的问题,取出了a中的成员对象b,随后可以对其进行操作
a.getB()是左值表达式,所以也可以这么用
a.getB() = B();
成员函数返回值为非常引用类型的目的可以说是为了避免拷贝以及可修改对象的内部数据

4:成员函数返回值为常引用类型
class B{};

class A
{
public:
const B& getB(){ return b; }
private:
B b;
};
可以这么调用成员函数
A a;
const B &bb = a.getB();
同样避免了拷贝问题,但是取出来的成员对象b不能在外部修改,
a.getB()是常量表达式,不能用于 = 左操作数,以及++,--操作符的操作数

那么可以得出一个结论就是,引用(常引用和非常引用)是为了防止拷贝,随后的操作是对源对象的操作,常引用进一步要求不修改源对象的值,如果返回类型为值类型,就不是操作源对象
这些问题在类的设计中是必须要考虑的问题,严重关系着程序的效率和执行的正确性,所以必须要清楚

下面是分析函数返回类型为值类型,C++语言是如何来实现的,解释为什么返回为值类型,在返回之前会发生拷贝
对于返回值为值类型,C++语言的实现
class A{};
1: A fun()
{
A ma;
//对ma做处理...
return ma;
}

实际上是函数1是这么实现的:
void fun(A &__result )
{
A ma;
ma.A::A();
//对ma做处理...
__result.A::A(ma);

return;
}
编译之后函数会转化为带一个参数的形式
如果这样调用函数:fun();
执行过程中会调用A::A()和A::A(const A&)
如果这样调用函数:A a = fun();
实际转化为fun(a);同样会调用A::A()和A::A(const A&)
如果涉及编译器层面的优化,会转为这样的形式
void fun(A &__result )
{
__result.A::A();
return;
}
直接用__result取代 ma,减少拷贝构造和析构的次数

如果返回值为引用类型,不清楚
...全文
136 点赞 收藏 3
写回复
3 条回复

还没有回复,快来抢沙发~

发动态
发帖子
C++ 语言
创建于2007-09-28

3.1w+

社区成员

24.8w+

社区内容

C++ 语言相关问题讨论,技术干货分享
社区公告
暂无公告