“纯虚函数调用”崩溃从何而来?

新手上路,请多包涵

我有时会注意到程序在我的计算机上崩溃并出现错误:“纯虚函数调用”。

当无法从抽象类创建对象时,这些程序如何编译?

原文由 Brian R. Bondy 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.4k
2 个回答

如果您尝试从构造函数或析构函数进行虚函数调用,则可能会导致它们。由于您不能从构造函数或析构函数调用虚函数(派生类对象尚未构造或已被销毁),因此它调用基类版本,在纯虚函数的情况下,不会不存在。

 class Base
{
public:
    Base() { reallyDoIt(); }
    void reallyDoIt() { doIt(); } // DON'T DO THIS
    virtual void doIt() = 0;
};

class Derived : public Base
{
    void doIt() {}
};

int main(void)
{
    Derived d;  // This will cause "pure virtual function call" error
}

另请参阅 Raymond Chen 关于该主题的 2 篇文章

原文由 Adam Rosenfield 发布,翻译遵循 CC BY-SA 4.0 许可协议

我遇到了纯虚函数因为对象被破坏而被调用的场景, Len Holgate 已经有一个很好的 答案,我想用一个例子添加一些颜色:

  1. 创建一个派生对象,并将指针(作为基类)保存在某处
  2. Derived 对象被删除,但仍以某种方式引用指针
  3. 指向已删除派生对象的指针被调用

Derived 类析构函数将 vptr 点重置为具有纯虚函数的基类 vtable,因此当我们调用虚函数时,它实际上调用的是纯虚函数。

这可能是由于明显的代码错误或多线程环境中竞争条件的复杂场景而发生的。

这是一个简单的例子(g++编译关闭优化 - 一个简单的程序可以很容易地被优化掉):

  #include <iostream>
 using namespace std;

 char pool[256];

 struct Base
 {
     virtual void foo() = 0;
     virtual ~Base(){};
 };

 struct Derived: public Base
 {
     virtual void foo() override { cout <<"Derived::foo()" << endl;}
 };

 int main()
 {
     auto* pd = new (pool) Derived();
     Base* pb = pd;
     pd->~Derived();
     pb->foo();
 }

堆栈跟踪如下所示:

 #0  0x00007ffff7499428 in __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:54
#1  0x00007ffff749b02a in __GI_abort () at abort.c:89
#2  0x00007ffff7ad78f7 in ?? () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#3  0x00007ffff7adda46 in ?? () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#4  0x00007ffff7adda81 in std::terminate() () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#5  0x00007ffff7ade84f in __cxa_pure_virtual () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#6  0x0000000000400f82 in main () at purev.C:22

强调:

如果对象被完全删除,这意味着析构函数被调用,并且内存被回收,我们可能会简单地得到一个 Segmentation fault 因为内存已经返回给操作系统,程序无法访问它。所以这种“纯虚函数调用”的场景通常发生在对象被分配到内存池上,而对象被删除时,底层内存实际上并没有被操作系统回收,它仍然可以被进程访问。

原文由 Baiyan Huang 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题