<转>C++分离式编译模型

本文转自:https://blog.csdn.net/uestclr/article/details/51372780

 

c++开发中广泛使用声明和实现分开的开发形式,其编译过程是分离式编译,就是说各个cpp文件完全分开编译,然后生成各自的obj目标文件,最后通过连接器link生成一个可执行的exe文件。

 

一、普通函数声明和实现分开的分离式编译

---------------test.h----------------------------------------------------------------------------------------------

  void fun();这里的.h文件只是声明一个函数f

---------------test.cpp-------------------------------------------------------------------------------------------

  #include”test.h”

  void fun()

  {

     std::cout<<"分离式编译"<<std::endl;

  } 这里给出了test.h中声明的f函数的具体实现

-----------------main.cpp----------------------------------------------------------------------------------------

  #include”test.h”

  int main()

  {

   fun(); 调用fun

  }

 

分别用g++ -c test.cpp,g++ -c mian.cpp编译两个cpp文件,g++ -c的作用是只是做编译工作生成.o文件,而不做链接的过程,此时得到了main.o和test.o两个目标文件。

用g++ -S main.cpp生成main.s的汇编文件,查看生成的汇编文件如下:

.file"main.cpp"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
call_Z3funv
movl $0, %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Ubuntu 4.8.4-2ubuntu1~14.04) 4.8.4"
.section .note.GNU-stack,"",@progbits

可以看到有一条语句call _Z3funv,这条语句表明调用了fun函数,这就说明,在编译main.cpp的时候,不需要知道fun函数的具体实现,只需要有个声明,然后会有一条call的指令,在链接的时候去其他的文件中寻找fun函数的具体实现,如果在链接的时候找不到这样一个fun函数,将会发生一个链接期错误。

 

二,为什么模版不能采用分离式编译

然而,对于模板,你知道,模板函数的代码其实并不能直接编译成二进制代码,其中要有一个实例化的过程。通常而言,并不是把模板编译成一个可以处理任何类型的实体,而是对于实例化模板的每种类型,都从模板产生出一个不同的实体。这种用具体类型代替模板参数的过程叫做实例化。它产生了一个模板的实例。只要使用函数模板,(编译器)会自动地引发这样一个实例化过程,因此程序员并不需要额外地请求对模板的实例化。

举个例子:


//-------------test.h-----------------------------------------------------------------------------------------------------------//

  template

  class A

  {

  public:

    void f();//这里只是个声明

  };

//---------------test.cpp------------------------------------------------------------------------------------------------------//

  #include”test.h”

  template

  voidA::f() //模板的实现,但注意:不是具现

  {

  …//dosomething

  }

 //---------------main.cpp---------------//

  #include”test.h”

  int main()

  {

    A a;

  a.f();
       }

在编译main.cpp的时候,文件中只有f的声明,所以只能寄托于在链接的时候找到f的实现,然而在链接的时候main能在test.cpp的目标文件中找到f的实现吗?这是不能的,由于是分离编译的,在编译test的时候,f函数并没有被使用到,所以也不会被实例化,没有被实例化就找不到对应的代码段,所以在链接的时候编译器就傻眼了。这就是为什么模板不能分离编译的原因。


关键是:在分离式编译的环境下,编译器编译某一个.cpp文件时并不知道另一个.cpp文件的存在,也不会去查找[当遇到未决符号时它会寄希望于连接器]。这种模式在没有模板的情况下运行良好,但遇到模板时就傻眼了,因为模板仅在需要的时候才会具现化出来,所以,当编译器只看到模板的声明时,它不能具现化该模板,只能创建一个具有外部连接的符号并期待连接器能够将符号的地址决议出来。

所以一般的操作也就是将模板的实现一起写在头文件.h中。

posted @ 2019-06-08 23:48  Royzzzzz  阅读(151)  评论(0编辑  收藏  举报