ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

基类没有虚析构函数,基类指针删除派生类对象,行为是未定义的

基类没有虚析构函数,基类指针删除派生类对象,行为是未定义的 polymorph源代码#includeiostream// /*structBase{virtualvoidf(){}};structDerived:Base{voidf()override{}};intmain(){Base*pnewDerived;return0;}// */C 基类指针删除派生类对象为什么需要虚析构函数polymorph.cpp当前启用的代码是Base*pnewDerived;目前没有delete p;所以这里是内存没有释放。如果加上delete p;确实会产生未定义行为。关键在于指针类型是Base*但它指向的完整对象是Derived。Base*pnewDerived;// ↑ ↑// 静态类型 动态类型delete p;需要完成两个步骤析构对象清理对象管理的资源。释放new分配的内存。为了正确销毁这个Derived对象需要先执行Derived的析构函数再执行Base的析构函数。虚析构函数提供了通过基类指针找到实际对象析构函数的机制。你的Base只有virtualvoidf(){}这只保证p-f()能调用Derived::f()。每个函数是否为虚函数是分别决定的f()是虚函数不会让析构函数自动变成虚函数。编译器隐式生成的Base::~Base()仍然是非虚的。没有虚析构时通常会按指针的静态类型选择Base::~Base()无法通过这条析构调用完成派生对象的清理。更复杂的继承结构还可能涉及基类子对象与完整对象的地址不同、释放内存时需要正确的对象大小等问题。因此C 对这里的普通单对象delete明确规定通过基类指针删除派生类对象基类必须具有虚析构函数否则行为未定义。要注意“只调用基类析构函数”只是常见表现不是标准保证的结果。即使你这里的Derived没有数据成员、没有资源要释放程序运行起来也正常仍然违反这条规则。修改为structBase{virtualvoidf(){}virtual~Base()default;};之后Base*pnewDerived;deletep;// 正确~Derived() → ~Base() → 释放内存Derived的析构函数会自动成为虚函数无须显式声明。文件中注释掉的std::unique_ptrBase版本也有同样的问题它的默认删除器最终执行的仍然是对Base*的delete因此也需要给Base添加虚析构函数。
返回列表