C++继承程序链接报错:undefined reference to vtable for C
三层C++继承程序链接报错:undefined reference to `vtable for C'
问题场景
我正在编写一个三层继承的C++程序,类结构为A基类,B继承A,C继承B,包含虚函数和分离的头文件实现。编译所有源文件成功,但链接阶段报错,提示找不到C类的虚函数表。
报错核心信息:
relocation against `_ZTV1C' in read-only section `.text' undefined reference to `vtable for C'
完整代码
A.h
#ifndef A_H_ #define A_H_ #include <string> #include <iostream> using namespace std; class A { protected: string name; public: A(string name); virtual ~A(); virtual void justATest(){} void justBecause(); virtual bool derivedTest(){} }; #endif /* A_H_ */
A.cpp
#include "A.h" A::A(string name) {this->name.assign(name);} A::~A() {} void A::justBecause(){}
B.h
#ifndef B_H_ #define B_H_ #include "A.h" #include <string> class B : public A{ public: B(string name):A(name){} virtual ~B(){} bool derivedTest(); }; #endif /* B_H_ */
B.cpp
#include "B.h" bool B::derivedTest() { return true; }
C.h
#ifndef C_H_ #define C_H_ #include "B.h" class C : public B{ public: C(string name) :B(name){} virtual ~C(){} void justATest(); }; #endif /* C_H_ */
C.cpp
#include "C.h" void C::justATest() { cout<< this->name; }
main.cpp
#include "C.h" int main(int argc, char* argv[]) { C* c = new C("str"); return 0; }
编译命令及错误详情
编译命令:
make all
完整错误输出:
Building target: demo_proj Invoking: GCC C++ Linker g++ -o "ass5_demo" ./A.o ./B.o ./C.o ./main.o /usr/bin/ld: ./main.o: warning: relocation against `_ZTV1C' in read-only section `.text._ZN1CC2ENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE[_ZN1CC5ENSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE]' /usr/bin/ld: ./main.o: in function `C::C(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >)': /home/some_user/eclipse-workspace/demo_proj/../C.h:14: undefined reference to `vtable for C' /usr/bin/ld: warning: creating DT_TEXTREL in a PIE
问题原因及解决方法
原因
GCC编译器下,当类包含非内联的虚函数(比如C::justATest()),同时将另一个虚函数(这里是析构函数~C())在头文件中内联定义时,编译器无法正确确定该类虚函数表(vtable)的生成位置。通常编译器会在包含类第一个非内联虚函数定义的编译单元中生成vtable,但内联析构函数会干扰这一逻辑,导致C.cpp中没有生成vtable,链接时其他编译单元找不到它。
解决方法
方法一:将C类的析构函数移到C.cpp中实现
修改C.h中的析构函数声明,只保留声明不定义:
class C : public B{ public: C(string name) :B(name){} virtual ~C(); // 移除内联定义 void justATest(); };
在C.cpp中添加析构函数的实现:
#include "C.h" void C::justATest() { cout<< this->name; } C::~C() {} // 添加析构函数实现
方法二:确保C类有一个内联的纯虚函数(可选)
在C类中添加一个内联的纯虚函数(比如空的虚函数),不过这种方法不如第一种规范,更推荐方法一。
修改后重新编译链接,即可解决报错。
内容的提问来源于stack exchange,提问作者MichaelK
相关产品推荐
相关产品推荐

