如果 vtable 是在编译时创建的,为什么这个错误是链接器错误而不是编译错误?
if vtable is created at compile time , why this error is an linker error and not compile error?
下面的一段代码报错了
undefined reference to `vtable for Derived'
代码:
#include <iostream>
class base{
public:
base(){}
virtual ~base(){}
virtual void test()
{
}
};
class Derived:public base{
public:
Derived(){}
~Derived(){}
void test();
};
int main() {
base* b = new Derived ();
delete b;
}
我的理解是因为 虚函数 test
已声明但未在 class Derived
.
中定义
但是当我使用 g++ -c file.cpp
编译时,根据 this C 编译或 assemble 源文件,但不 link。它不会给我任何错误并且可以正常编译。因此,上述错误是在 linking 时间而不是 compile 时间生成的。
据我了解, vtable
不是在编译时创建的。那为什么我在编译时自己没有得到错误?
我得到了什么 g++ foo.cpp -v
/tmp/ccBc4VPu.o: In function `Derived::Derived()':
foo.cpp:(.text._ZN7DerivedC2Ev[_ZN7DerivedC5Ev]+0x1f): undefined reference to `vtable for Derived'
collect2: error: ld returned 1 exit status
这是一个 链接器 错误,本身不是编译器错误。
错误的根本原因是test
是在Derived中声明的,但并没有真正实现。链接器给出了令人困惑的错误消息。它应该为缺少的 Derived::test
方法
声明一个错误
GCC 有一个 FAQ entry 解决这个问题:
When building C++, the linker says my constructors, destructors or virtual tables are undefined, but I defined them
The solution is to ensure that all virtual methods that are not pure are defined. Note that a destructor must be defined even if it is declared pure-virtual [class.dtor]/7.
编译器不需要所有方法都可用。他有他们的宣言就够了。
此方法可以在不同的编译单元(cpp/cxx 文件)中实现,因此对于编译器而言,甚至无法检查此方法是否在其他地方可用。编译器一次处理一个 cpp 文件。
将方法和调用匹配在一起是链接器的工作。
然而你形成了必须在编译时创建 vtable 的观点,你错了。
分离编译是标准中的一个核心概念。这就是编译单元(又名源文件)可以编译的原因,只要它需要任何函数声明 - 即使它没有定义的可见性。
在典型的 "compile then link" 构建链中,这允许编译单元(源文件)进行编译,给定可能在另一个编译单元中定义的函数(成员函数或非成员函数)的任何声明。
链接器需要检测函数定义的缺失。
实际上,这意味着编译器可能会发出有关 vtable 的信息,但链接器将(咳咳)将 vtable 的规范链接到实际的成员函数。
下面的一段代码报错了
undefined reference to `vtable for Derived'
代码:
#include <iostream>
class base{
public:
base(){}
virtual ~base(){}
virtual void test()
{
}
};
class Derived:public base{
public:
Derived(){}
~Derived(){}
void test();
};
int main() {
base* b = new Derived ();
delete b;
}
我的理解是因为 虚函数 test
已声明但未在 class Derived
.
但是当我使用 g++ -c file.cpp
编译时,根据 this C 编译或 assemble 源文件,但不 link。它不会给我任何错误并且可以正常编译。因此,上述错误是在 linking 时间而不是 compile 时间生成的。
据我了解, vtable
不是在编译时创建的。那为什么我在编译时自己没有得到错误?
我得到了什么 g++ foo.cpp -v
/tmp/ccBc4VPu.o: In function `Derived::Derived()':
foo.cpp:(.text._ZN7DerivedC2Ev[_ZN7DerivedC5Ev]+0x1f): undefined reference to `vtable for Derived'
collect2: error: ld returned 1 exit status
这是一个 链接器 错误,本身不是编译器错误。
错误的根本原因是test
是在Derived中声明的,但并没有真正实现。链接器给出了令人困惑的错误消息。它应该为缺少的 Derived::test
方法
GCC 有一个 FAQ entry 解决这个问题:
When building C++, the linker says my constructors, destructors or virtual tables are undefined, but I defined them
The solution is to ensure that all virtual methods that are not pure are defined. Note that a destructor must be defined even if it is declared pure-virtual [class.dtor]/7.
编译器不需要所有方法都可用。他有他们的宣言就够了。
此方法可以在不同的编译单元(cpp/cxx 文件)中实现,因此对于编译器而言,甚至无法检查此方法是否在其他地方可用。编译器一次处理一个 cpp 文件。
将方法和调用匹配在一起是链接器的工作。
然而你形成了必须在编译时创建 vtable 的观点,你错了。
分离编译是标准中的一个核心概念。这就是编译单元(又名源文件)可以编译的原因,只要它需要任何函数声明 - 即使它没有定义的可见性。
在典型的 "compile then link" 构建链中,这允许编译单元(源文件)进行编译,给定可能在另一个编译单元中定义的函数(成员函数或非成员函数)的任何声明。
链接器需要检测函数定义的缺失。
实际上,这意味着编译器可能会发出有关 vtable 的信息,但链接器将(咳咳)将 vtable 的规范链接到实际的成员函数。