一道2011年阿里巴巴笔试题,主要考察派生类构造函数的执行过程
#include<iostream>
using namespace std;
class A
{
public:
A() { cout<<"A"<<endl; }
~A() { cout<<"~A"<<endl; }
};
class B:public A
{
public:
B(A &a):_a(a)
{
cout<<"B"<<endl;
}
~B()
{
cout<<"~B"<<endl;
}
private:
A _a;
};
int main(void)
{
A a;
B b(a);
return 0;
}
输出:
A
A
B
~B
~A
~A
~A。
创建派生类对象时,程序首先调用基类构造函数,然后再调用派生类的构造函数。基类构造函数负责初始化继承的数据成员;派生类构造函数主要用于初始化新增的数据成员。派生类的构造函数总是调用一个基类构造函数。可以使用初始化列表句法指明要使用的基类构造函数,否则使用默认的基类构造函数。
派生类过期时,程序将首先调用派生类析构函数,再调用基类的析构函数。
执行A a;
调用A类的默认构造函数A(),将输出A
执行 B b(a);
首先将调用A类的默认构造函数A(),这将输出A。
然后在成员初始化列表中,用输入的参数a来初始化b对象的一个成员_a(_a的类型是A),这将调用A类的拷贝构造函数,但是程序中并没有显式定义,
那么编译器将自动生成一个隐式的拷贝构造函数(这个隐式的拷贝构造函数执行成员复制,属于浅拷贝)。
然后再执行B类的构造函数,则输出B。
综上B b(a);此语句的调用构造函数的顺序是 A()->A的默认拷贝构造函数,来初始化_a->B();
当执行完return 0后,执行析构函数。
先调用B类的析构函数~B(),这将输出~B
再调用A类的析构函数~A()去处理b对象中的成员_a.这将输出~A。
再调用A类的析构函数~A()去处理b对象中的基类部分。这将输出~A。
因为a对象定义的比b对象早,所以被释放的就晚(考虑对象建立在堆栈中,堆栈是先入后出)
所以最后调用A类的析构函数~A(),这将输出~A。