c++子类析构函数未调用

发布于 2022-09-11 16:40:07 字数 502 浏览 23 评论 0

为什么父类的析构函数定义成virtual后, delete pTest2 就会释放Derived的资源, 否则就只能释放Base的资源, 而delete pTest1就能释放Derived 和Base的资源

class Base
{
public:
    ~Base() {
        cout << "Base destructor!" << endl;
    };
};

class Derived: public Base
{
public:
    ~Derived() {
        cout << "Derived destructor!" << endl;
    };
};

int main() {

    Derived *pTest1 = new Derived();
    Base *pTest2 = new Derived();

    delete pTest1;
    delete pTest2;
    return 0;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

我的痛♀有谁懂 2022-09-18 16:40:07

delete的语义就是调用析构函数
如果析构函数有virtual修饰,C++保证delete调用子类析构,插在析构前面。

本身一个delete一个指针只会调用本身的析构。

思慕 2022-09-18 16:40:07
class Base
{
public:
    ~Base() {
        ...;
    };
};

Base *pTest2 = ...;
delete pTest2;

仔细看这个代码,执行delete pTest2时,编译器并不知道pTest2指向的是一个Base子类!他只知道指向的是类Base!

烟凡古楼 2022-09-18 16:40:07

只能说 cpp 就是这么设计的. 你可说它(被)设计的不好.

sf上有个问题:什么时候不用 virtual destructor?

供参考
https://stackoverflow.com/que...

虚函数意味着每个分配的对象都会通过虚函数表指针增加内存开销。

因此,如果您的程序涉及分配大量的某些对象,那么为了节省每个对象的额外32位,值得避免所有虚函数。

在所有其他情况下,您将节省自己的调试痛苦,使析构函数虚拟化。

天赋异禀 2022-09-18 16:40:07

以下只是个人理解,如有谬误请指出,谢谢。

首先需要明确两个概念:

第一个是 virtual 的意义,
当我们通过指针调用一个类对象的方法时,编译器只有指针类型和指向地址这两个信息,它只能根据指针类型来推断指向的对象实例在内存里实际长什么样,
当我们调用的是一个 non-virtual 方法时,C++ 只能根据指针类型来判断应该调用的方法,如果这个指针是一个基类指针,即使它指向的是一个子类对象,但编译器不知道啊,所以它只会调用基类中的对应方法。
只有声明了 virtual,C++ 才会在对象实例中创建一个 virtual table,里面包含了这个类对象实际持有的所有 virtual 函数的地址,此时我们通过一个基类指针指向子类对象,调用 virtual 方法,C++ 会到这个虚函数表中调用对应位置的函数指针,自然就能正确调用子类的方法了。

第二个是析构函数的运作方式,
当我们调用一个 class 的析构函数,从这个 class 起,依次往上,每个 base class 的析构函数都会逐个被调用。
这也是为什么 delete 子类指针,子类和父类的析构函数都会被正确调用的原因。

显然,当一个 derived class 对象,经由一个 base class 指针删除时,
如果这个 base class 的析构函数是 non-virtual 的,C++ 就会直接调用 base class 的析构函数,derived class 的析构函数自然得不到执行,
当这个 base class 的析构函数是 virtual 的,C++ 在 vtbl 中找到这个对象实例所持有析构函数的函数指针,并调用它,然后根据析构函数的基本运作方式,子类先调用,基类后调用。

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文