跟Java一样,如果类里面的成员是另一个类,则在初始化时成员类先初始化,如下:
class A {
public:
A() {
printf("A()\n");
}
~A() {
printf("~A()\n");
}
};
class B {
public:
A a; // A的构造先执行
B() { // B的构造后执行
printf("B()\n");
}
~B() {
printf("~B()\n");
}
};
int main() {
B b;
return 0;
}
执行结果如下:
A()
B()
~B()
~A()
可以看到,B中包含A,则创建B时,A先被创建完成,然后B才能创建完成,回收时相反,B先被回收,然后再回收A。
再改一下代码:
#include <cstdio>
class A {
public:
A() {
printf("A()\n");
}
~A() {
printf("~A()\n");
}
};
class B {
public:
A a; // A的构造先执行
B(A tempA) { // B的构造后执行
printf("B()\n");
}
~B() {
printf("~B()\n");
}
};
int main() {
A a;
B b(a);
return 0;
}
输出结果如下:
A()
A()
B()
~A()
~B()
~A()
~A()
这里看到A只打印了两次A的构造函数调用,但是却打印了A的3次析构调用,这说明已经创建了3个A对象了,为什么构造函数只打印了两次,因为有一次是调用的拷贝构造函数,我们没写拷贝构造函数,则系统会为我们生成一个,分析如下:
验证一下,在A中添加拷贝构造函数,如下:
A(const A & a) {
printf("A(const A & aReference)\n");
}
运行结果如下:
A()
A(const A & aReference)
A()
B()
~A()
~B()
~A()
~A()
main函数中B b(a);,B的构造函数如下:
B(A tempA) {
printf("B()\n");
}
B b(a);这里的传参操作,实际是下面的赋值语句:
A tempA(a);
所以B(A tempA)构造函数中的参数A tempA是使用拷贝构造函数创建出来的一个新对象。
我们把B构造函数再修改一下,使用初始化列表为初始化成员a,如下:
B(A tempA) : a(tempA) {
printf("B()\n");
}
运行结果如下:
A()
A(const A & a)
A(const A & a)
B()
~A()
~B()
~A()
~A()
这时候可以看到A的两次拷贝构造。有点奇怪,按理解:main函数中A a;会调一次空构造函数,B类中的A a;也会调用一次构造函数,但是从打印结果看只调用了一次,这是因为B类中的A a;并没有走空构造函数,因为B在B的构造函数中初始化成员A a:B(A tempA) : a(tempA),这里的B(A tempA)在参数传递时执行了一次A的拷贝构造函数,在调用成员列表初始化a(tempA)时,又再一次调用了A的拷贝构造函数,因为编译器知道B中的成员变量在B的构造函数中有初始化列表,所以成员声明A a;就不使用默认的空构造初始化了。