分离式编译

最近的工作中需要用到类模板。声明模板类放在头文件里,然后犯了个错误把 类的成员函数定义按照惯例放在了一个CPP文件里。编译虽然过了,但是链接也会出问题。

这里开始找找原因,原来类模板不支持分离编译。

C++编译过程分几步。第一 预编译 
这一步可以粗略的认为只做了一件事情,那就是宏展开,也就是对那些#***的命令的一种展开,例如define MAX 1000就是建立起MAX1000之间的对等关系,好在编译阶段进行替换。例如ifdef/ifndef就是从一个文件中有选择性的挑出一些符合条件的代码来交给下一步的编译阶段来处理。这里面最复杂的莫过于include了,其实也很简单,就是相当于把那个对应的文件里面的内容一下子替换到这条include***语句的地方来。  
这也是为什么 需要在头文件里 有预编译头 来处理 避免重新展开了该头文件 保证每个头文件最多被展开一次
#ifndef _WIN32_WINNT            // Specifies that the minimum required platform is Windows Vista.
#define _WIN32_WINNT 0x0600     // Change this to the appropriate value to target other versions of Windows.
#endif

编译:C++标准中提到,一个编译单元[translation unit]是指一个.cpp文件以及它所include的所有.h文件,.h文件里的代码将会被扩展到包含它的.cpp文件里,然后编译器编译该.cpp文件为一个.obj文件,后者拥有PE[Portable Executable,即windows可执行文件]文件格式,并且本身包含的就已经是二进制码,但是,不一定能够执行,因为并不保证其中一定有main函数。
链接:当编译器将一个工程里的所有.cpp文件以分离 的方式编译完毕后,再由连接器(linker)进行连接成为一个.exe文件。

由于在类模板中编译过程中 还没有实现“具体实现化”的一个过程。模板函数的代码其实并不能直接编译成二进制代码。所有在分离编译的CPP文件 编译器不会去理会的。

关于模板类分离编译 链接失败的原因分析 找到了比较好的答案:
关键是:在分离式编译的环境下,编译器编译某一个.cpp文件时并不知道另一个.cpp文件的存在,也不会去查找[当遇到未决符号时它会寄希望

于连接器]。这种模式在没有模板的情况下运行良好,但遇到模板时就傻眼了,因为模板仅在需要的时候才会具现化出来,所以,当编译器只看

到模板的声明时,它不能具现化该模板,只能创建一个具有外部连接的符号并期待连接器能够将符号的地址决议出来。然而当实现该模板

的.cpp文件中没有用到模板的具现体时,编译器懒得去具现,所以,整个工程的.obj中就找不到一行模板具现体的二进制代码,于是连接器也傻眼。

经过消化 也就是说上面一段内容指的是,在其他CPP文件还没有利用到模板类的时候,编译器编译其它CPP文件,不需要去找模板类具体化的二进制代码,所以链接不会错误,但是如果其他CPP文件里用到模板类,那么它就寄希望于链接到二进制代码。可以分离编译模式下,正在编译的某CPP不知道 类模板定义的CPP文件的存在,它只知道
类模板的H文件。如果模板在H文件里 定义好了 那么就可以被编译器具体化 生成需要的二进制代码链接进去。

换句话说 模板类 不能同其他类一样生成obj,它只能附属到调用它的CPP编译单元去具体化产生二进制代码。我想这个二进制代码属于具体化它的cpp的obj里面的。

欢迎指正!


类模版定义和Inline函数定义在.h里,非inline函数和静态放在.cpp里。这种方式可以减少编译相同的函数模版定义会增加的不必要的编译时间。比如,类模板的定义在a.h里,该类的成员函数和静态成员在a.cpp里,而主函数等一些用户程序的使用在main.cpp里。这里,涉及到“可导出的类模板”。
可导出的类模板:当他的成员函数实例或者静态实例被使用时,编译器只要求类模板的定义。即使一个类模板自身被声明为可导出的,export也只是单纯的使成员函数和静态可以在程序文本中不可见,而其自身的定义也仍然是必须得。
BUT,因为编译的时候每次只执行一个文件,如果一个成员函数多次被定义,编译器也不能出错,但是,链接时刻就有错误了。或者就是出错,或者就是由编译器可能用一个可导出的模板定义实例化该成员忽略其他的定义。
当然也有好处了。把接口和具体实现分离开来:接口在.h,实现在.c。不需要用户知道具体细节,只用他们需要的函数就可以了。
P.S.使用包含编译模式的时候,成员的定义被包含在我们所说的主函数所在的.cpp里面。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值