构造函数的调用顺序:自上而下
- 当建立一个对象时,首先调用基类的构造函数,然后调用下一个派生类的构造函数,依次类推,直至到达最底层目标派生类的构造函数
析构函数的调用顺序:自下而上
- 当删除一个对象时,首先调用该派生类的析构函数,然后调用上一层基类的析构函数,依次类推,直到到达最顶层的基类析构函数
代码演示
#include <iostream>
using namespace std;
class Base {
public:
Base() { cout << "创建Base基类。" << endl; }
~Base() { cout << "删除Base基类。" << endl; }
};
class Child : public Base {
public:
Child() { cout << "创建Child派生类。" << endl; }
~Child() { cout << "删除Child派生类。" << endl; }
};
int main() {
cout << "*********构造函数调用顺序示例***********" << endl;
Child *C1 = new Child;//派生类指针指向派生类对象
cout << "*********析构函数调用顺序示例***********" << endl;
delete C1;
}
-
输出结果
创建Base基类。 创建Child派生类。 *********析构函数调用顺序示例*********** 删除Child派生类。 删除Base基类。
虚析构函数的作用
通过基类指针来删除派生类对象时,基类的析构函数应该是虚函数
- 在公有继承中,基类对派生类及其对象的操作,只能影响到那些从基类继承下来的成员。如果要用基类对继承成员进行操作,则要把基类的这个成员函数定义为虚函数,析构函数同样需要如此。
- 如果要用基类指针来删除派生类的对象,而这个基类有一个非虚的析构函数。后果是对象的派生部分不会被销毁。然而基类部分被销毁了,将导致内存泄露。
基类析构函数不是虚函数,则析构的时候子类对象没有析构
#include <iostream>
using namespace std;
class Base {
public:
Base() { cout << "创建Base基类。" << endl; }
~Base() { cout << "删除Base基类。" << endl; } //析构函数不是虚函数
};
class Child : public Base {
public:
Child() { cout << "创建Child派生类。" << endl; }
~Child() { cout << "删除Child派生类。" << endl; }
};
int main() {
cout << "*********构造函数调用顺序示例***********" << endl;
Base *C1 = new Child;//基类指针指向派生类对象
cout << "*********析构函数调用顺序示例***********" << endl;
delete C1;
}
-
输出结果
*********构造函数调用顺序示例*********** 创建Base基类。 创建Child派生类。 *********析构函数调用顺序示例*********** 删除Base基类。
基类析构函数是虚函数,子类对象和父类对象都被析构
#include <iostream>
using namespace std;
class Base {
public:
Base() { cout << "创建Base基类。" << endl; }
virtual ~Base() { cout << "删除Base基类。" << endl; } //虚析构函数
};
class Child : public Base {
public:
Child() { cout << "创建Child派生类。" << endl; }
~Child() { cout << "删除Child派生类。" << endl; }
};
int main() {
cout << "*********构造函数调用顺序示例***********" << endl;
Base *C1 = new Child;
cout << "*********析构函数调用顺序示例***********" << endl;
delete C1;
}
-
输出结果
*********构造函数调用顺序示例*********** 创建Base基类。 创建Child派生类。 *********析构函数调用顺序示例*********** 删除Child派生类。 删除Base基类。