与函数相比,链接阶段没有类重定义错误的原因?

时间:2018-04-24 15:54:31

标签: c++

据我所知,如果我在A.h中定义非内联函数,并在A.hmain.cpp中包含A.cpp。然后会出现功能重新定义错误。 示例代码如下:

A.H:

void hello(){}  

A.cpp:

#include "A.h"

main.cpp中:

#include "A.h"

但是,如果我在A.h中定义一个类,在A.hmain.cpp中包含A.cpp,那么为什么没有类重新定义错误 }?

A.H:

class A{};

A.cpp:

#include "A.h"

main.cpp中:

#include "A.h"

以类似内联函数的方式处理类进程(我对内联函数进程的了解很少,但我听说内联函数有一些标记,编译器(或链接器?)将删除所有其他定义副本最后留下一个定义)?

1 个答案:

答案 0 :(得分:4)

有两种方法可以回答这个问题。我们可以查看C ++标准以了解规则的含义,并且我们可以查看编译器的实际实现,以了解为什么在实践中会发生这种情况。

  • 如果我们正在查看C ++标准,则会有一条称为One Definition Rule或ODR的规则。 ODR说类可以在多个翻译单元中定义,但定义必须相同(使用.h文件可以很容易地保证这一点)。但非内联函数只能在单个翻译单元中定义。

  • 如果我们查看编译器的实际实现,这种行为的原因很简单。类定义不会将任何内容输出到.o文件中(除了某些调试信息之外)。另一方面,函数定义输出一些编译的目标代码以及符号表条目。

如果检查目标文件的内容,则可以看到此操作:

$ cat test.cc
class Foo {};
void hello() {}
$ g++ -c -o test.o test.cc
$ nm test.o
0000000000000000 T __Z5hellov

test.cc中我定义了一个类和一个函数。但是这个类没有向目标文件中发出任何东西,只有函数发生了。这就是为什么当两个.o文件定义同一个类时没有冲突的原因。

内联函数需要特殊处理以避免导致链接错误。它们被放在称为COMDAT部分的特殊部分中。您可以阅读有关此here的更多信息。