C++模板的编译与连接
2015-11-17 18:28
405 查看
C++的编译是以.cpp文件为单位进行。编译之前存在一个预处理的过程:文件包含,条件编译和宏展开。文件包含是将include 的头文件中的内容复制到.cpp文件中。一般接口与实现的分离设计,头文件中通常都是函数和类的声明。
在编译的过程中,如果A.cpp文件中有函数 f() 的调用,但是不存在 f() 函数的定义;那么在编译f() 函数时,将调用语句编译为外部链接的调用指令(call + 经过namemagling 处理之后的函数名称),得到 A.obj文件;在连接的过程中,会在其他 .obj 目标文件中找到函数f()的二进制代码(通过符号导入表和符号导出表快速查找)地址, 将 A.obj 中的那条外部链接指令替换为实际函数的二进制地址(编译之后的目标 .obj文件都是二进制文件)。
对于函数,只有当发生调用才会被实例化,才会被编译为二进制代码。
所以如果分离编译模板,例如A.cpp 文件中调用一个函数模板 f(T t), 调用语句为 f(8); 因为此时在A.cpp文件中看不到 f(T t) 的定义,所以无法实例化,所以编译过程同上边是一样的,最后 A.obj 目标文件中调用语句被编译为外部链接调用指令,将插入实际实例化的二进制代码的地址的工作,不过编译器在编译包含模板模板 f(T t)的定义的源文件 B.cpp 时,由于只是定义,而没有发生调用,所以将不会实例化f(T t), B.obj
目标文件中也就得不到 f() 函数的二进制代码! 所以链接器在寻找 f() 的二进制代码时将发生失败,只能给出一条连接错误了。
所以如果B.h文件中有 f(T t) 的定义,在A.cpp 包含 B.h 的时候,f(T t)定义将随着B.h 文件中的所有内容插入到A.cpp当中,于是,在编译时,A.cpp中的 f(T t) 函数调用能够看到其定义,所以 最终A.obj文件中将直接包含 f() 函数的二进制代码!
在编译的过程中,如果A.cpp文件中有函数 f() 的调用,但是不存在 f() 函数的定义;那么在编译f() 函数时,将调用语句编译为外部链接的调用指令(call + 经过namemagling 处理之后的函数名称),得到 A.obj文件;在连接的过程中,会在其他 .obj 目标文件中找到函数f()的二进制代码(通过符号导入表和符号导出表快速查找)地址, 将 A.obj 中的那条外部链接指令替换为实际函数的二进制地址(编译之后的目标 .obj文件都是二进制文件)。
对于函数,只有当发生调用才会被实例化,才会被编译为二进制代码。
所以如果分离编译模板,例如A.cpp 文件中调用一个函数模板 f(T t), 调用语句为 f(8); 因为此时在A.cpp文件中看不到 f(T t) 的定义,所以无法实例化,所以编译过程同上边是一样的,最后 A.obj 目标文件中调用语句被编译为外部链接调用指令,将插入实际实例化的二进制代码的地址的工作,不过编译器在编译包含模板模板 f(T t)的定义的源文件 B.cpp 时,由于只是定义,而没有发生调用,所以将不会实例化f(T t), B.obj
目标文件中也就得不到 f() 函数的二进制代码! 所以链接器在寻找 f() 的二进制代码时将发生失败,只能给出一条连接错误了。
所以如果B.h文件中有 f(T t) 的定义,在A.cpp 包含 B.h 的时候,f(T t)定义将随着B.h 文件中的所有内容插入到A.cpp当中,于是,在编译时,A.cpp中的 f(T t) 函数调用能够看到其定义,所以 最终A.obj文件中将直接包含 f() 函数的二进制代码!
相关文章推荐
- C++ 学习
- C语言运算符优先级误解
- 编写configure.ac
- STL: reverse_iterator / iterator 关系以及 erase 相关(C++)
- 转载关于char的c语言指针问题:char **s char *a [ ] char a [ ]
- 浅析C语言编程中的数组越界问题
- 【C语言】【面试题】【笔试题】调整数组使奇数全部都位于偶数前面
- 通过一个小例子来简单理解C语言中的内存空间管理
- 对C语言编程标准以及声明的基本理解
- C++字符串转化为数字的库函数
- C++字符串类型和数字之间的转换
- C++OOP程序设计读书笔记之一:面向对象的程序设计简介
- 【黑马程序员】C语言—推箱子游戏实现
- 【黑马程序员】C语言—通讯录系统的实现
- C语言基本数据类型
- C语言基础-- 冒泡排序,字符串数组
- POJ 2352 Stars
- 【黑马程序员】C语言字符串
- C语言1.用选择法对10个整数排序。10个整数用scanf函数输入。
- 【黑马程序员】C语言函数