该错误源于多重继承下虚函数表(vtable)中thunk生成失败,主因是基类析构函数未声明为virtual,或虚函数重写签名不一致(如const、noexcept、引用限定符 mismatch),亦可能因模板虚函数定义位置不当导致ODR违反。

这个错误只出现在多重继承且含虚函数的场景中
“error: non-virtual thunk to ...”不是你代码写错了语法,而是编译器在生成虚函数表(vtable)时,为解决多重继承下的 this 指针偏移问题而插入的“thunk”(跳转桩)出了矛盾。它几乎总是意味着:某个类同时继承了多个带虚函数的基类,且其中至少一个基类的析构函数没声明为 virtual,或者虚函数重写签名不一致(比如 const 修饰、引用限定符、noexcept 声明不匹配)。
最常见诱因:基类析构函数没加 virtual
尤其当父类被用作多态接口时,缺少 virtual 析构函数会导致对象销毁行为未定义,而编译器在生成 thunk 时会检测到 vtable 不一致,直接报这个错。
- 检查所有被继承的基类,尤其是提供接口的抽象基类,确认其析构函数是否为
virtual ~Base() = default;或virtual ~Base() {} - 如果基类有虚函数但析构函数是隐式非 virtual 的(比如只写了
~Base() {}),立刻补上virtual - 注意:派生类析构函数即使不显式写
virtual,也会自动继承虚性;但基类必须显式声明
虚函数重写签名不一致也会触发
C++ 要求重写(override)必须与基类虚函数的签名完全一致(返回类型协变除外)。哪怕差一个 const、一个 &&、或一个 noexcept,编译器就可能拒绝生成正确的 thunk,转而报这个看似无关的错误。
- 用
override关键字强制检查:把疑似重写的函数末尾加上override,编译器会明确告诉你哪里不匹配 - 特别注意 const 成员函数:基类是
virtual int get() const;,派生类写成int get();就不行 - 检查引用限定符(
&/&&)和异常规范(noexcept),它们都属于函数类型的一部分
模板类/内联定义位置不当可能干扰 vtable 生成
如果涉及模板基类,或虚函数定义分散在头文件和 .cpp 中(尤其是 inline 函数体放在 .cpp 里),链接期可能看不到完整定义,导致不同编译单元对同一虚函数的 this 偏移计算不一致,进而破坏 thunk 逻辑。
立即学习“C++免费学习笔记(深入)”;
- 确保所有虚函数(包括纯虚)的声明和定义——如果定义是 inline 的——必须全部落在头文件中
- 模板类中的虚函数不能分离声明/定义;否则实例化时可能缺失 vtable 条目
- 检查是否在某个 .cpp 里 #include 了部分头文件但漏掉了关键虚函数定义,造成 ODR 违反
这个错误本质是编译器在说:“我算出来的 this 偏移在不同上下文里打架了”。它不指向某一行代码,而指向整个继承结构的设计一致性。最容易被忽略的是:你以为只是加个 virtual 就完事,但其实 const/noexcept/引用限定符这些细节,一个不匹配,thunk 就建不起来。


















