Skip to content

败犬日报 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