C++中为什么要将析构函数设为virtual
来源:互联网 发布:tomcat端口有哪些 编辑:程序博客网 时间:2024/04/30 13:11
要回答这个问题,首先需要弄清楚的问题是,在C++中类的构造函数、析构函数的调用次序是什么?
这里指假设基类和派生类的成员中,包含其他类的对象。
在C++中,构造函数的调用次序是:
基类的成员->基类的构造函数体->派生类的成员->派生类的构造函数体
析构函数的调用次序是:
派生类的析构函数->派生类的成员析构->基类的析构函数->基类的成员析构
下面的例子给出了形象的展示:
#include <iostream>using namespace std;class AA{public: AA() { cout<<"AA Construct"<<endl; } ~AA() { cout<<"AA Destroy"<<endl; }};class BB{public: BB() { cout<<"BB Construct"<<endl; } ~BB() { cout<<"BB Destroy"<<endl; }};class Base{public: Base() { cout<<"Base Construct"<<endl; } ~Base() { cout<<"Base Destroy"<<endl; }private: AA aa;};class Derive: public Base{public: Derive() { cout<<"Derive Construct"<<endl; } ~Derive() { cout<<"Derive Destroy"<<endl; }private: BB bb;};int main(){ Derive d; /*运行结果 AA Construct Base Construct BB Construct Derive Construct Derive Destroy BB Destroy Base Destroy AA Destroy */}
运行截图如下:
但是当涉及多态时,使用基类指针指向 new创建的派生类对象时,情况就有所不同了
#include <iostream>using namespace std;class AA{public: AA() { cout<<"AA Construct"<<endl; } ~AA() { cout<<"AA Destroy"<<endl; }};class BB{public: BB() { cout<<"BB Construct"<<endl; } ~BB() { cout<<"BB Destroy"<<endl; }};class Base{public: Base() { cout<<"Base Construct"<<endl; } ~Base() { cout<<"Base Destroy"<<endl; }private: AA aa;};class Derive: public Base{public: Derive() { cout<<"Derive Construct"<<endl; } ~Derive() { cout<<"Derive Destroy"<<endl; }private: BB bb;};int main(){ Base *p = new Derive; delete p; /*运行结果 AA Construct Base Construct BB Construct Derive Construct Base Destroy AA Destroy */}
运行截图如下:
从程序的运行情况来看,我们不难发现,在最后释放指针p所指向的对象时,只释放了基类的部分,没有释放派生类的部分。这是因为,指针p声明时是基类的指针,而基类的析构函数不是虚函数,所以调用那个析构函数是在编译时确定的。如果要执行正确的析构顺序,需要将基类的析构函数定义为 virtual, 这样派生类的析构函数就自动是virtual的了,在最后释放指针p时,按照RTTI,执行p所指真实对象的析构函数。
下面是将基类的析构函数指定为virtual时,(派生类析构函数自动为virtual)
#include <iostream>using namespace std;class AA{public: AA() { cout<<"AA Construct"<<endl; } ~AA() { cout<<"AA Destroy"<<endl; }};class BB{public: BB() { cout<<"BB Construct"<<endl; } ~BB() { cout<<"BB Destroy"<<endl; }};class Base{public: Base() { cout<<"Base Construct"<<endl; } virtual ~Base() { cout<<"Base Destroy"<<endl; }private: AA aa;};class Derive: public Base{public: Derive() { cout<<"Derive Construct"<<endl; } ~Derive() { cout<<"Derive Destroy"<<endl; }private: BB bb;};int main(){ Base *p = new Derive; delete p; /*运行结果 AA Construct Base Construct BB Construct Derive Construct Derive Destroy BB Destroy Base Destroy AA Destroy */}
运行截图如下:
0 0
- C++中为什么要将析构函数设为virtual
- 基类的析构函数为什么要设为Virtual
- 多态时最好将基类的析构函数设为virtual
- 为什么不能把构造函数设为虚函数,却可以把析构函数设为虚函数
- C++里父类的析构函数为什么声明为virtual
- 析构函数为什么要设置为virtual
- 为什么内联函数,构造函数,静态成员函数不能为virtual函数
- 为什么内联函数,构造函数,静态成员函数不能为virtual函数
- 为什么内联函数,构造函数,静态成员函数不能为virtual函数
- 为什么内联函数,构造函数,静态成员函数不能为virtual函数?
- 为什么内联函数,构造函数,静态成员函数不能为virtual函数
- 为什么内联函数,构造函数,静态成员函数不能为virtual函数
- 为什么内联函数,构造函数,静态成员函数不能为virtual函数
- 为什么基类的析构函数要设为虚函数
- 为什么析构函数可以为virtual型,而构造函数则不能?
- 为什么要把父类的析构函数设置为virtual
- 为什么要将析构函数定义为虚函数
- 不能为virtual 的函数
- MySQL中concat函数(连接字符串)
- 建食堂
- JS 整型,浮点型转化为字符型
- zthread学习 三 使用Executor器来执行线程
- uva 202求循环小数
- C++中为什么要将析构函数设为virtual
- zthread学习 实例四 让步、休眠、优先级
- [Python]网络爬虫(一):抓取网页的含义和URL基本构成
- Matlab中一个很有用的函数:regionprops
- zthread学习 实例五 非任务对象的生存期
- [Python]网络爬虫(二):利用urllib2通过指定的URL抓取网页内容
- JSP页面显示倒计时
- 简明Vim练级攻略
- LeetCode---(83) Remove Duplicates from Sorted List