当析构函数调用抽象函数时会发生什么

时间:2018-02-13 13:45:54

标签: c++ constructor crash virtual abstract

我无法理解以下代码中发生崩溃的原因:

class A {
public:
    virtual ~A() { goo(); }
    void goo() { absFoo(); }
    virtual void absFoo() = 0;

};

class B : public A {
public:
    void absFoo() { cout << "In B \n"; }
};

int main() 
{
    B b1;
    b1.goo();
}

主要版画&#34;在B&#34;正如预期的那样,但最终当它崩溃时,我也无法调试它,编译器会弹出一个奇怪的消息。

所以我的问题是,当A的析构函数调用&#34; goo()&#34;时,&#34; absFoo()&#34 ;,崩溃 因为我们指的是抽象函数?

编译器实际上是否在派生类中寻找定义?(并且它不再存在,因为它预先被破坏所以它崩溃了)

我知道如果我们打电话给#34; absFoo()&#34;直接来自析构函数,原因就是抽象函数。但是因为在这里它是一个外部函数调用&#34; absFoo()&#34;我无法理解真正的原因。

3 个答案:

答案 0 :(得分:19)

  

析构函数调用抽象函数时会发生什么

首先,让我们考虑一下析构函数调用任何虚函数时会发生什么(顺便说一下,这同样适用于构造函数):当在foo的析构函数中调用虚函数T时,调用不会动态调度到派生类型的实现(任何派生对象的生命周期已经结束),但静态调度到实现T::foo

如果T::foo是纯虚拟的,那么在没有动态调度的情况下调用它将具有未定义的行为。这就是在析构函数(或构造函数)中(间接)调用纯虚函数时会发生的情况。

答案 1 :(得分:11)

只是为了补充已经接受的答案,这是来自cppreference的文档。

  

直接或间接从a调用虚函数时   构造函数或析构函数(包括在构造期间或   破坏类的非静态数据成员,例如在一个成员   初始化列表),以及调用适用的对象是   正在建设或破坏的对象,被称为的函数是   构造函数或析构函数类中的最终覆盖而不是一个   在更派生的类中重写它。

     

换句话说,在构建或销毁期间,不存在更多派生的类。

答案 2 :(得分:5)

当对象被解构时,vtable会更新以匹配对象的新状态。

由于您删除了最后一个函数,编译器将执行它认为合适的任何操作;在Visual Studio中进行调试编译的情况下,将回退到报告纯虚函数被调用的中止。

然而,vtable不是标准的一部分,它是一个实现细节,并且不要求程序崩溃;当你调用纯虚函数时,这才是最好的事情。