为什么类的定义应当写在头文件中,从而被多个源文件包含?

比如myclass.h定义了一个类myclass(只定义类,不定义成员函数),
file1.cpp里#include "myclass.h",编译得到file1.obj;
file2.cpp里也#include "myclass.h",编译得到file2.obj;
那么把file1.obj和file2.obj(和运行库)连接起来生成可执行文件的时候,为什么不会有冲突呢?2个文件都包含了myclass类的定义。

答:

因为这遵守“单一定义规则”(One-Definition Rule, ODR)。根据此规则, 如果对同一个类的两个定义完全相同且出现在不同编译单位,会被当作同一个定义。
这里头文件分别被两个不同的编译单位(file1.cpp, file2.cpp)包含,满足ODR规则,会被当作同一个定义。 所以不会有冲突。
此外,模板和inline函数也适用此规则。
追问
类的定义在目标文件比如file1.obj里是怎么体现的呢?它产生目标代码吗?类的定义不是变量名,也不是函数名,那么在代码段、数据段或符号表里面应该都没有条目?
还是说,类的定义只是让编译器识别下文的这个类名?而对目标文件没有任何体现?
回答
细节依赖于编译器的实现。
以g++为例,类的代码出现在包含类方法定义的编译单元,引用他的编译单元会在链接时寻找类代码。如果.h中在类定义大括号内直接定义了函数,
那么类代码会出现在每一个include这个.h的编译单元中。 以前者为例:
myclass.h:
class MyClass
{
public: MyClass(int i);
  void add();
  int m;
};

myclass.cpp:
#include "myclass.h"
MyClass::MyClass(int i)
{
this->m = i;
  add();
}
void MyClass::add()
{
this->m ++;
}
file1.cpp:
#include "myclass.h"
void f1()
{
MyClass mc(10);
}
file2.cpp:
#include "myclass.h" void f2()
{
MyClass mc(20);
}
main.cpp:
int main()
{
 void f1();
void f2();
f1();
f2();
}

可见类代码在myclass.o, file1.o在类定义的帮助下,通过_ZN7MyClassC1Ei引用类方法代码。
其它细节可以反汇编代码、看elf/pe等文件格式文档以及编译器源代码。
所谓的编译只编译cpp文件,.h文件不参与编译,头文件的作用就是告诉编译器,
有这个类,但是类的实现在其他位置,编译时,编译器不会去找类的实现,
链接时编译器才会去寻找这个类的实现。

 

posted @ 2014-12-28 10:06  BAOXF  阅读(659)  评论(0编辑  收藏  举报