昨天做了网易的实习生笔试(一首凉凉送给自己),其中有道问答题是这样的
1 #include<iostream> 2 using namespace std; 3 class A 4 { 5 public: 6 A(){cout<<"A"<<endl;} 7 ~A(){cout<<"~A"<<endl;} 8 9 }; 10 11 class B : public A 12 { 13 public: 14 B(A &a):_a(a){cout<<"B"<<endl;} 15 B(){cout<<"B"<<endl;} 16 ~B(){cout<<"~B"<<endl;} 17 private: 18 A _a; 19 }; 20 21 int main() 22 { 23 A a; 24 B b(a); 25 }
指出基类构造函数、派生类构造函数,派生类成员变量构造函数的调用顺序,并出他们的析构函数调用顺序。
代码运行结果如下:
首先是类A的实例a,输出第一行的“A”;因为B是A的派生类,B在实例化时会先调用A的构造函数,然后调用自己的构造函数(见链接),所以其次输出第二行“A”和第三行“B”。
然后是b的析构,先调用派生类(自己)的析构函数,将成员变量_a析构然后调用父类的析构函数,这对应第四、第五和第六行的输出。第七行为a的析构。
这时候问题就来了,为什么B的成员变量_a在初始化的时候没有调用A的构造函数?
原来是因为在初始化_a的时候使用了初始化列表,此时会调用A的拷贝构造函数(当我们没有定义拷贝构造函数时,编译器会为我们定义一个),故没有输出“A”。
若我们显示的定义一个拷贝构造函数:
1 class A 2 { 3 public: 4 A(){cout<<"A"<<endl;} 5 A(const A &a){cout<<"copy A"<<endl;} 6 ~A(){cout<<"~A"<<endl;} 7 8 };
结果如下: