析构函数中的virtual是否必要?
我们经常听到建议要把构造函数不能为虚,析构函数最好为虚,这是为什么?
如下例子:
// pvtable1.cpp : 定义控制台应用程序的入口点。
#include "stdafx.h" #include <iostream> using namespace std; class Base1 { public: Base1(){ cout << "Base1::Base1()" << endl; } ~Base1(){ cout << "Base1::~Base1()" << endl; } virtual void f() { cout << "Base1::f" << endl; } virtual void g() { cout << "Base1::g" << endl; } virtual void h() { cout << "Base1::h" << endl; } }; class Base2 { public: Base2(){ cout << "Base2::Base2()" << endl; } ~Base2(){ cout << "Base2::~Base2()" << endl; } virtual void f() { cout << "Base2::f" << endl; } virtual void g() { cout << "Base2::g" << endl; } virtual void h() { cout << "Base2::h" << endl; } }; class Base3 { public: Base3(){ cout << "Base3::Base3()" << endl; } ~Base3(){ cout << "Base3::~Base3()" << endl; } virtual void f() { cout << "Base3::f" << endl; } virtual void g() { cout << "Base3::g" << endl; } virtual void h() { cout << "Base3::h" << endl; } }; class Derive : public Base1, public Base2, public Base3 { public: Derive(){ cout << "Derive::Derive()" << endl; } ~Derive(){ cout << "Derive::~Derive()" << endl; } virtual void f() { cout << "Derive::f" << endl; } virtual void g1() { cout << "Derive::g1" << endl; } }; int doIt2() { Base1 *pBase1 = new Derive(); delete pBase1; return 0; } int _tmain(int argc, _TCHAR* argv[]) { doIt2(); return 0; }
当使用一个多重继承的时候,使用父类的指针删除子类的时候,发现了不能正常析构的情况,执行结果如下:
如果在将父类的析构函数定义为虚函数,便正常了
一个类中将所有的成员函数都尽可能地设置为虚函数总是有益的。虽然会增大开销
下面是设置虚函数的注意事项:
1、只有类的成员函数才能声明为虚函数。
2、静态成员函数不能使虚函数,因为它不受限于某个对象。
3、内联函数不能使虚函数。
4、构造函数不能是虚函数。
不用virtual 的几种情况:
1、作为非公有基类。仅作为 private base class 使用的 class 不需要使用虚拟析构函数
2、不作为接口使用的基类。
3. 如果你可以保证这个类不被public继承(private/protected继承的话,在非friend函数/类中就无法用基类指针指向派生类了)
4. 如果它的所有派生类(包括派生类的派生类)的析构函数都是trivial的(这里的trivial指的是在程序员的层次什么事也不做)
5. 如果不需要用基类的指针指向派生类的对象
在这五种情况下,不把析构函数声明为virtual都是可以的,何况效率会高一些——但前提是你得保证前提的成立——不过这些保证常常是很难100%的:谁能保证别人在派生你的类的时候,析构函数是trivial的,或者别人不用你提供的基类的指针指向派生类对象?这些常常是很难得到保证的。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现