文档章节

类模板的编译

chelseablood
 chelseablood
发布于 2014/12/23 20:55
字数 1076
阅读 20
收藏 0

声明模板类放在头文件里,然后犯了个错误把 类的成员函数定义按照惯例放在了一个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里面的。


本文转载自:

上一篇: return 0的意义
下一篇: C++中的引用
chelseablood
粉丝 0
博文 16
码字总数 34846
作品 0
海淀
私信 提问
C++的模板机制

为什么需要模板编程 所谓函数模板,实际上是建立一个通用函数,其函数返回类型、形参类型或函数中使用的类型不具体指定,用一个虚拟的类型来代表,这个通用函数就称为函数模板 所谓类模板,和...

沙米笔记
2016/05/28
736
2
关于ZThread编译不过的问题解决办法

下了一个开源的线程库zthread,2.3.2版本的,有错,在linux下不 能编译通过,疯,后来改了点代码才编译过。 后来找到了原因: 代码里用到了模板继承,当子类和父类都是模板类时,子类函数调用...

华宰
2011/06/30
1K
1
C++中的特化问题和类型萃取问题

模板的特化 概念  从字面上来解释,就是为已有的模板参数进行一些使其特殊化的指定,使得以前不受任何约束的模板参数,或受到特定的修饰(例如const或者摇身一变成为了指针,甚至是经过别的...

qq_38646470
2018/05/13
0
0
C++泛型编程学习(一)

目录 前言 从接触到泛型编程都现在决定写博客,不知道过去多久的时间,感觉每次记得,然后每次都会忘记,所以没有记录的工作,基本等于没做。。某句话就是,一旦你今天想要完成的事情没有完成...

simonforfuture
2017/12/28
0
0
深入探讨vc下C++模板编译模型

写过模板的朋友也许知道,一个模板程序,当编译器看到模板定义时并不立即产生代码,只有在我们用到模板,并对其实例化的时候,才会产生特定的实例。此时,编译器就要访问定义模板的源代码了。...

zjushawnelee88
2013/06/19
159
0

没有更多内容

加载失败,请刷新页面

加载更多

Spring使用ThreadPoolTaskExecutor自定义线程池及实现异步调用

多线程一直是工作或面试过程中的高频知识点,今天给大家分享一下使用 ThreadPoolTaskExecutor 来自定义线程池和实现异步调用多线程。 一、ThreadPoolTaskExecutor 本文采用 Executors 的工厂...

CREATE_17
今天
5
0
CSS盒子模型

CSS盒子模型 组成: content --> padding --> border --> margin 像现实生活中的快递: 物品 --> 填充物 --> 包装盒 --> 盒子与盒子之间的间距 content :width、height组成的 内容区域 padd......

studywin
今天
7
0
修复Win10下开始菜单、设置等系统软件无法打开的问题

因为各种各样的原因导致系统文件丢失、损坏、被修改,而造成win10的开始菜单、设置等系统软件无法打开的情况,可以尝试如下方法解决 此方法只在部分情况下有效,但值得一试 用Windows键+R打开...

locbytes
昨天
8
0
jquery 添加和删除节点

本文转载于:专业的前端网站➺jquery 添加和删除节点 // 增加一个三和一节点function addPanel() { // var newPanel = $('.my-panel').clone(true) var newPanel = $(".triple-panel-con......

前端老手
昨天
8
0
一、Django基础

一、web框架分类和wsgiref模块使用介绍 web框架的本质 socket服务端 与 浏览器的通信 socket服务端功能划分: 负责与浏览器收发消息(socket通信) --> wsgiref/uWsgi/gunicorn... 根据用户访问...

ZeroBit
昨天
10
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部