以下以一个例子说明C++中返回值为对象的过程详解。
#include <iostream>
using namespace std;
//建一个Test类
class Test
{
public:
Test()
{
a = 0;
b = 0;
cout << "无参构造函数被调用了" << endl;
}
Test(int aa, int bb)
{
a = aa;
b = bb;
cout << "有参构造函数被调用了" << endl;
}
Test(const Test& t)
{
a = t.a;
b = t.b;
cout << "复制构造函数被调用了" << endl;
}
void print()
{
cout << "a:" << a << endl << "b:" << b << endl;
}
~Test()
{
cout << "析构函数被调用了" << endl;
}
private:
int a;
int b;
};
//以下为几个方便说明的操作函数
Test g()
{
Test tt(11, 22);
return tt;
}
void play1()
{
g();
}
void play2()
{
Test t1 = g();
t1.print();
}
void play3()
{
Test t2(3,4);
t2.print();
t2 = g();
t2.print();
}
//主函数
int main()
{
play1();
调用此句时,g()被调用,首先在g()函数中创建一个tt对象,随后调用复制构造函数,由tt对象给产生的匿名对象初始化,随后tt对象被析构,在play1()中,因为g()中的匿名对象并没有给任何对象初始化或复制,因此在play1()中,又会调用析构函数将当做参数传回来的匿名对象析构掉,因此结果为:play2();
调用此句时,g()调用部分与上例相似,不同的是g()传回来的参数给t1这个对象初始化,编译器在处理这句话时并没有创建一个新的对象来接受g()返回来的匿名对象的值,而是采取了优化,直接将这个匿名对象扶正,给其一个名字叫t1,所以匿名对象没有析构,随后可以打印t1(),当play2()函数结束时,才会将t1析构掉,结果如下play3();
play3()和play2()的区别在于,g()返回值(即匿名对象)并没有给一个对象初始化,而是赋值!!!t2这个对象已经存在了,有了确定的内存空间,所以匿名对象不会扶正,匿名对象的作用是给这个t2对象重新赋值,t2=g()这句话会调用赋值构造函数(而不是复制构造函数),因此结果如下
system("pause");
return 0;
}
以上程序运行结果跑在Visual Studio2015Debug环境下,如果跑在Release环境下的话结果会不同,Debug方便调试,Release是发布版本,进行了一系列的优化改进