标签:
Q1. 以下代码的输出结果是什么?
1 #include <iostream> 2 using namespace std; 3 4 class A 5 { 6 public: 7 A() { cout << "A" << endl; } 8 ~A() { cout << "~A" << endl; } 9 }; 10 class B : public A 11 { 12 public: 13 B(A &a) : _a(a) { cout << "B" << endl; } 14 ~B() { cout << "~B" << endl; } 15 private: 16 A _a; 17 }; 18 19 int main(int argc, char *argv[]) 20 { 21 A a; 22 B b(a); 23 return 0; 24 }
Q2. Test执行后输出的结果为()
1 void Test () 2 { 3 class B 4 { 5 public: 6 B() { cout << "B\t"; } 7 ~B() { cout << "~B\t"; } 8 }; 9 struct C 10 { 11 C(void) { cout << "C\t"; } 12 ~C(void) { cout << "~C\t"; } 13 }; 14 struct D : B 15 { 16 public: 17 D() { cout << "D\t"; } 18 ~D() { cout << "~D\t"; } 19 private: 20 C c; 21 }; 22 D d; 23 }
A. B C D ~D ~C ~B
B. D C B ~B ~C ~D
C. C D B ~B ~D ~B
D. C ~C D ~D B ~B
1. 析构函数
构造函数的一个用途自动获取资源。例如,构造函数可以分配一个缓冲区或打开一个文件,在构造函数中分配了资源之后,需要一个对应的操作自动回收或释放资源。析构函数就是这样的一个特殊函数,它可以完成所需的资源回收,作为类函数的补充。
当对象超出作用域或动态分配的对象被删除时,将自动应用析构函数。析构函数可用于释放对象构造时或在对象的生命周期中所获得的资源。
不管类是否定义了自己的析构函数,编译器都自动执行类中非static数据成员的析构函数。
虽然构造函数不对定义成虚函数,但析构函数可以定义为虚函数,一般来说,如果类中定义了虚函数,析构函数也应该被定义为虚函数,尤其是类内有申请的动态内存,需要清理和释放的时候。
2. 构造函数与析构函数的调用顺序
(1) 单继承
派生时,构造函数和析构函数是不能继承的,为了对基类成员进行初始化,必须对派生类重新定义构造函数和析构函数,并在构造函数的初始化列表中调用基类的构造函数。
由于派生类对象通过继承而包含了基类数据成员,因此,创建派生类时,系统首先通过派生类的构造函数来调用基类的构造函数,完成基类成员的初始化,而后对派生类中新增的成员进行初始化。
派生类构造函数的一般格式为:
1 派生类名(总参数表) : 基类构造函数(参数表) 2 { 3 // 函数体 4 }
必须将基类的构造函数放在派生类的初始化列表中,以调用基类构造函数完成基类数据成员的初始化(若无,则调用基类的默认构造函数),派生类构造函数实现的功能,或者说调用顺序为:
1). 完成对象所占整块内存的开辟,由系统在调用构造函数时完成;
2). 调用基类的构造函数完成基类成员的初始化;
3). 若派生类中含对象成员、const成员或引用成员,则必须在初始化表中完成其初始化;
4). 派生类构造函数体执行。
当对象被删除时,派生类的析构函数被执行。析构函数不能继承,因此,在执行类析构函数时,基类析构函数会被自动调用。执行顺序是先执行派生类的析构函数,再执行基类的析构函数,这和执行构造函数时的顺序正好相反。
(2) 多继承
多继承时,派生类的构造函数初始化列表需要调用各个基类的构造函数。而析构函数的顺序依然按照构造函数运行的逆序执行。
注意:此时构造函数初始化列表只能控制用于初始化基类的值,不能控制基类的构造次序。基类构造函数按照基类构造函数在类派生列表中的出现次序调用。
例如,有如下的继承关系:
1 #include <iostream> 2 using namespace std; 3 4 class ZooAnimal 5 { 6 public: 7 ZooAnimal() { cout << "ZooAnimal" << endl; } 8 ~ZooAnimal() { cout << "~ZooAnimal" << endl; } 9 }; 10 class Bear : public ZooAnimal 11 { 12 public: 13 Bear() { cout << "Bear" << endl; } 14 ~Bear() { cout << "~Bear" << endl; } 15 }; 16 class Endangered 17 { 18 public: 19 Endangered() { cout << "Endangered" << endl; } 20 ~Endangered() { cout << "~Endangered" << endl; } 21 }; 22 class Panda : public Bear, public Endangered 23 { 24 public: 25 Panda() : Endangered(), Bear() { cout << "Panda" << endl; } 26 ~Panda() { cout << "~Panda" << endl; } 27 }; 28 29 int main(int argc, char *argv[]) 30 { 31 Panda p; 32 return 0; 33 }
分析:
(3) 虚继承
首先调用虚基类的构造函数,虚基类如果有多个,则虚基类构造函数的调用顺序是此虚基类在当前类派生表中出现的次序而不是它们在成员初始化表中的顺序。
所有虚基类的构造函数调用完毕后,然后按照(2)的规则调用其他的构造函数。
标签:
原文地址:http://www.cnblogs.com/xiaoxxmu/p/5734985.html