败犬日报 2025-02-04
1. 运行报错 "pure virtual method called"
这个问题一般是基类构造时、析构时或者析构后调用了纯虚函数。
例如下面代码就是析构后调用了纯虚函数:
cpp
#include <cstdlib>
#include <new>
struct A {
virtual void foo() = 0;
virtual ~A() = default;
};
struct B : A {
void foo() override {}
};
int main() {
B* b = (B*)malloc(sizeof(B));
new (b) B();
A *a = b;
b->~B();
a->foo(); // pure virtual method called
free(b);
return 0;
}
代码在 GCC 14.2 不加优化时会报 "pure virtual method called",加 O2 优化会正常退出(因为是未定义行为,发生什么都合理)。
https://zh.cppreference.com/w/cpp/language/virtual 有记载:
在构造和析构期间,进一步的派生类并不存在,如同*this的动态类型是正在构造的类的静态类型(动态派发不在继承层级下传)。
因此一个可能的实现是,B 构造依次执行 A, B 的构造函数,虚表指针也会依次指向 A, B 的虚表。析构则是倒过来。
https://itanium-cxx-abi.github.io/cxx-abi/abi.html#pure-virtual 有记载,存虚函数在虚表里也会有表项。例如,GCC 给 A 虚表的 foo 一个占位符号 __cxa_pure_virtual,它负责直接 terminate:
text
vtable for A:
.quad 0
.quad typeinfo for A
.quad __cxa_pure_virtual
.quad 0
.quad 0
cpp
LIBCXXABI_NORETURN
void __cxa_pure_virtual(void) {
abort_message("Pure virtual function called!");
}
这下就能解释了。
扩展阅读:调用 deleted 虚函数的相关问题 https://stackoverflow.com/questions/30596591/when-is-cxa-deleted-virtual-called。