C ++为什么不按运行时类型销毁对象?

时间:2019-03-05 04:55:02

标签: c++ rtti

据我所知,当基类具有虚函数时,C ++可以获取对象动态类型的准确信息。

class Base
{
public:
    Base() {}
    ~Base() { std::cout << "Base Destructed" << std::endl; }

    virtual void f() {}
};

class Derived : public Base
{
public:
    Derived() {}
    ~Derived() { std::cout << "Derived Destructed" << std::endl; }
};

void PrintTypeName(Base *p)
{
    std::cout << typeid(*p).name() << std::endl;
}

int main()
{
    Base *p = new Derived();
    PrintTypeName(p);
    delete p;
}

上面的代码可以打印正确的对象类型,但是为什么它不能调用正确的析构函数。

我在g ++和Windows编译器上对其进行了测试,它们给出了相同的结果。我知道如果我使Base析构函数virtual可以正确地分解。

但是我想知道为什么不通过typeid调用析构函数。

2 个答案:

答案 0 :(得分:6)

如果某个方法未标记为virtual,则该方法不会存储在虚拟表中。在这种情况下,析构函数不会存储在虚拟表中。因此它不能被调用。

使用当前代码, vtables 将如下所示:

vtable for Derived:
        .quad   0
        .quad   typeinfo for Derived
        .quad   Base::f()
vtable for Base:
        .quad   0
        .quad   typeinfo for Base
        .quad   Base::f()

请参见 Demo here

如果在virtual中将析构函数标记为Base,则 vtables 将如下所示:

vtable for Derived:
        .quad   0
        .quad   typeinfo for Derived
        .quad   Derived::~Derived() [complete object destructor]
        .quad   Derived::~Derived() [deleting destructor]
        .quad   Base::f()
vtable for Base:
        .quad   0
        .quad   typeinfo for Base
        .quad   Base::~Base() [complete object destructor]
        .quad   Base::~Base() [deleting destructor]
        .quad   Base::f()

请参见Demo here

答案 1 :(得分:0)

如果您打算从基类析构函数派生类,请务必记住使它成为基类析构函数virtual

在基类中将其标记为虚拟将告诉编译器,它也希望在删除基对象的同时销毁派生对象。

class Base
{
public:
    Base() {}
    virtual ~Base() { std::cout << "Base Destructed" << std::endl; }

    virtual void f() {}
};

但是需要注意的一点是,您不会将虚拟放在函数的前面,而您不想覆盖它们。因为这样做会增加维护虚拟表的成本。

https://www.crashhandler.com/2019/03/make-destructors-destroy-virtually.html这是我对此的博客文章。