我有时会注意到程序在我的计算机上崩溃并出现错误:“纯虚函数调用”。
当无法从抽象类创建对象时,这些程序如何编译?
原文由 Brian R. Bondy 发布,翻译遵循 CC BY-SA 4.0 许可协议
我有时会注意到程序在我的计算机上崩溃并出现错误:“纯虚函数调用”。
当无法从抽象类创建对象时,这些程序如何编译?
原文由 Brian R. Bondy 发布,翻译遵循 CC BY-SA 4.0 许可协议
我遇到了纯虚函数因为对象被破坏而被调用的场景, Len Holgate
已经有一个很好的 答案,我想用一个例子添加一些颜色:
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 许可协议
3 回答2k 阅读✓ 已解决
2 回答3.9k 阅读✓ 已解决
2 回答3.2k 阅读✓ 已解决
1 回答3.2k 阅读✓ 已解决
1 回答2.7k 阅读✓ 已解决
3 回答3.4k 阅读
1 回答1.6k 阅读✓ 已解决
如果您尝试从构造函数或析构函数进行虚函数调用,则可能会导致它们。由于您不能从构造函数或析构函数调用虚函数(派生类对象尚未构造或已被销毁),因此它调用基类版本,在纯虚函数的情况下,不会不存在。
另请参阅 Raymond Chen 关于该主题的 2 篇文章