由于奇怪的ld错误,我长时间一直撞在墙上。 所以我在一个小的测试用例中重现了它以理解这个问题。
我宣布了一个类,我在头文件中派生了另一个:
class BaseClass {
public:
BaseClass(){};
virtual void func(){};
};
class DerivedClass: public BaseClass {
public:
DerivedClass();
void func();
};
然后我定义了构造函数,但忘了定义func
(这里是自愿的,但实际上我用愚蠢的复制/粘贴做了...):
DerivedClass::DerivedClass(){
cout << "Derived constructor" << endl;
}
//void DerivedClass::func(){
// cout << "Derived func" << endl;
//}
然后我得到:
未定义引用`vtable for DerivedClass'
编辑:该消息指出了构造函数的声明!
如果我取消注释func
的定义,那么我没有错误。所以我的问题:
为什么链接器没有告诉我func
的定义丢失了?
当你有经验时,解决方案可能很明显,但对于像我这样的初学者来说,它不是!
感谢您的帮助。
答案 0 :(得分:3)
vtable
是为包含虚函数的类和从它派生的类创建的。这意味着在您的程序vtable
中将为BaseClass
和DerivedClass
创建。这些vtables
中的每一个都包含虚函数void func()
的地址。现在请注意DerivedClass
不包含void func()
的定义,因此vtable
包含BaseClass
的{{1}}函数的地址。这就是编译器提供错误void func()
的原因。
答案 1 :(得分:0)
您的编译器似乎没有为vtable
生成DerivedClass
。 vtable
基本上是一个包含每个虚函数的函数指针的表。通过为每个对象存储指向类vtable
(通常称为vptr
)的指针,可以在运行时确定要调用的正确虚函数。虽然它是特定编译器的实现细节,但这是实现虚拟函数的常用方法,虚函数在运行时绑定,因此不能像普通函数一样调用。
我的第一个猜测是编译器没有为vtable
生成DerivedClass
因为它没有定义任何虚函数所以它使用BaseClass
的{{1}} }}。虽然这有点奇怪,但这是我能提出的唯一想法。但我并不精通编译器架构,也许有人有更好的解决方案。