先帖段代码,再慢慢分析吧
// project1.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include<string.h> struct A{ A(){puts("A()");};//默认构造函数 A(int v){puts("A(int)");};//重载构造函数 A(const A&){puts("A(A&)");};//拷贝或复制构造函数 A& operator=(const A &){//赋值构造函数 puts("operator=(A&)"); return *this; } ~A(){puts("~A()");} }; struct X{ X(int v){ a=v; } A a; ~X(){puts("~X()");}; }; int main(){ X slow(int(2)); return 0; }
输出结果为下图
下面具体分析下C++都做了什么。。。
代码执行到X slow(int(2))的时候,当执行到X(int v),首先执行初始化列表,然后在执行函数体之前初始化成员变量,当然这里的初始化列表没有内容,所以没有执行什么,然后此时会先初始化该类的成员变量,也就是A a,于是会打印第一个A(),接下来进入X的构造函数体,执行a=v,由于v是int类型,此时C++编译器会做隐式类型转换,通过A(int)构造函数构造出一个临时对象,用v进行初始化,所以会打印第二句A(int),接下来才会执行赋值运算符,打印第三句operator=(A&),当来到X(int)的函数体尾部,这个临时对象会被析构,于是打印了第四句~A(),析构时会按照构造函数的逆序先执行~X()函数,然后再析构成员变量,于是分别打印出~X(),~A()。
于是整个流程大致为:X(int) ---> 初始化列表 --> 成员变量 --> X(int)函数体 --> 创建临时对象A(int),A.operator=(),~A() --> 按逆序析构
作为成员变量与继承的对比,下面再帖一段相似的继承的例子
struct X2:public A{ X2(int v){ a=v; } A a; ~X2(){puts("~X2()");}; }; int main(){ X2(int(2)); return 0; }
此时输出结果如下
打印的结果与上述相比,仅仅在上述的结果首尾多了个A()和~A()。这是因为基类的初始化是在初始化列表之前,析构也是在最后.