跟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;就不使用默认的空构造初始化了。