我无法理解以下代码中发生崩溃的原因:
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;我无法理解真正的原因。
答案 0 :(得分:19)
析构函数调用抽象函数时会发生什么
首先,让我们考虑一下析构函数调用任何虚函数时会发生什么(顺便说一下,这同样适用于构造函数):当在foo
的析构函数中调用虚函数T
时,调用不会动态调度到派生类型的实现(任何派生对象的生命周期已经结束),但静态调度到实现T::foo
。
如果T::foo
是纯虚拟的,那么在没有动态调度的情况下调用它将具有未定义的行为。这就是在析构函数(或构造函数)中(间接)调用纯虚函数时会发生的情况。
答案 1 :(得分:11)
只是为了补充已经接受的答案,这是来自cppreference的文档。
直接或间接从a调用虚函数时 构造函数或析构函数(包括在构造期间或 破坏类的非静态数据成员,例如在一个成员 初始化列表),以及调用适用的对象是 正在建设或破坏的对象,被称为的函数是 构造函数或析构函数类中的最终覆盖而不是一个 在更派生的类中重写它。
换句话说,在构建或销毁期间,不存在更多派生的类。
答案 2 :(得分:5)
当对象被解构时,vtable会更新以匹配对象的新状态。
由于您删除了最后一个函数,编译器将执行它认为合适的任何操作;在Visual Studio中进行调试编译的情况下,将回退到报告纯虚函数被调用的中止。
然而,vtable不是标准的一部分,它是一个实现细节,并且不要求程序崩溃;当你调用纯虚函数时,这才是最好的事情。