当一个类中嵌入的有另一个类时,如果没有对内嵌对象初始化,则先对内嵌的默认缺省构造(有的话也是先对内嵌的不过是调用非缺省构造),再执行外层类的构造,析构时先析构外层类,再析构内层类。
我们来看一下下面这段代码的构造函数和析构函数的顺序:
#include<iostream>
#include<string>
using namespace std;
string GetMyString()
{
return "This is a string";
}
class zheng
{
private:
int a;
public:
zheng() { a = 0;
cout << "Mvalue copy construct" << endl; };
zheng(zheng& z){
cout << "Lvalue copy construct" << endl;
}
zheng(zheng && z){
cout << "Rvalue copy construct" << endl;
}
zheng(const int&& x):a(x){
cout << "value copy construct" << endl;
}
~zheng(){
cout << "destruct construct" << endl;
}
void set(int b)
{
a = b;
}
};
struct test
{
private:
zheng a;
public:
test( zheng& s)
{
cout << "L zheng construct" << endl;
}
test( zheng&& s)
{
cout << "R zheng construct" << endl;
}
~test(){
cout << " zheng destruct" << endl;
}
};
zheng GetMyvalue()
{
zheng x1;
// cout << " construct" << endl;
//x1.set(7);
//zheng x2(x1);
return x1;
}
int main(int argc, char const *argv[])
{
// {
// const string &s = GetMyString();//这种左引用的语法,会先调用默认构造函数开辟内存空间,然后再将引用,引用并不会调用构造函数
// }
// string a = "1234";
{
// GetMyvalue();
//zheng s(GetMyvalue());
//zheng y = s;
test s{GetMyvalue()};
// zheng s;
// zheng *p = &s; //这边只会调用一次构造函数,说明引用并不会调用构造函数
// zheng &x1 = s;
}
return 0;
}
打印结果:
第一个是在执行GetMyvale()函数中执行zheng x1;调用的构造函数;
第二个是在将GetMyvale()返回的对象赋值给test s时调用的test类构造函数,因为test类中有内嵌的对象,所以要先给内嵌的对象进行默认构造;
第三个是内嵌的对象构造完毕就开始构造自己的,因为rerun返回的是临时值也即右值,所以调用的是右值引用构造函数;
第四个是函数GetMyvale()中的对象x1调用的析构函数,这里有人会有疑问了为什么不是return完就调用析构函数,而是要test的对象都构造完了才开始析构呢?
这个很好理解,因为我要将return的对象传给了test对象才能析构(也就是让test的对象都构造完了才能释放内存),不然还没传就析构删除了,test接收了个寂寞,要等参数接收完了才删除!
这里其实还有个细节,如果是之前的版本的话,在return之前x1是要析构的
但是这里会在多一个构造函数要return时要在建一个零时对象来传递x1;但是c++最新的特性有个RVO,返回值优化,就把这个建立零时对象给优化了,减少了使用内存空间,从而也就需要完成零时对象的任务,在传完参数后再析构。
第五个就是调用了test的析构函数,这里就是因为栈的内存空间是先存后去,这种格式,后构造的外层test对象要先析构删除,在析构内层的zheng对象。