C++ 中Template 类、函数的编译过程
来源:互联网 发布:淘宝量子恒道统计 编辑:程序博客网 时间:2024/06/05 16:36
array.hpp
template <typename T, int SIZE>class array{T data_ [SIZE];array (const array& other);const array& operator = (const array& other);public:
array(){};void print_array(T b);T& operator[](int i) {return data_ [i];}const T& get_elem (int i) const {return data_ [i];}void set_elem(int i, const T& value) {data_ [i] = value;}operator T*() {return data_ ;}};
然后在main.cpp文件中的主函数中使用上述模板:
main.cpp
#include "array.hpp"
using namespace std;int main(void){array<int, 50> intArray;intArray.set_elem(0, 2);int firstElem = intArray.get_elem(0);int* begin = intArray;//intArray.printarray(5);return 0;}
这时编译和运行都是正常的。程序先创建一个含有50个整数的数组,然后设置数组的第一个元素值为2,再读取第一个元素值,最后将指针指向数组起点。
问题1: 在array.hpp中我们有很多函数没有只有声明没有定义 ,如voidprint_array(Tb),编译器为什么不给报错说有函数没有实现呢?
问题2:为什么当我们把main.cpp的intArray.print_array(5);去掉注释之后为什么才会报:main.cpp:12: error: undefined reference to `array<int, 50>::printarray(int)'?
带着这些两问题我们来看另一种情况,也就是传统编写头文件和cpp的方式。将array.hpp文件分裂成为array.h和array.cpp二个文件。
main.cpp
#include "array.h"using namespace std;int main(void){array<int, 50> intArray;intArray.set_elem(0, 2);int firstElem = intArray.get_elem(0);int* begin = intArray;//intArray.print_array(5);return 0;}
array.h
template <typename T, int SIZE>class array{T data_ [SIZE];array (const array& other);const array& operator = (const array& other);public:
array(){};void print_array(T b);T& operator[](int i);const T& get_elem (int i) const;void set_elem(int i, const T& value) ;operator T*() ;};
array.cpp
#include "array.h"template<typename T, int SIZE> T& array<T, SIZE>::operator [](int i){return data_[i]; }template<typename T, int SIZE> const T& array<T, SIZE>::get_elem(int i) const{return data_[i]; }template<typename T, int SIZE> void array<T, SIZE>::set_elem(int i, const T& value){data_[i] = value; }template<typename T, int SIZE> array<T, SIZE>::operator T*(){return data_; }
问题3:为什么这种声明和实现分开的方式会报错,而写在一起就不会?
问题4:这种写法在编译时会出现下面的错误:
main.cpp:9: error: undefined reference to `array<int, 50>::set_elem(int, int const&)'
main.cpp:10: error: undefined reference to `array<int, 50>::get_elem(int) const'
main.cpp:11: error: undefined reference to `array<int, 50>::operator int*()'
error: ld returned 1 exit status
可是我们明明已经在array里写了这些函数的实现啊,这是为什么 ?
问题5:array中有多于3个函数,为什么只有3个没有找到定义?
现在一一解释这5个问题。问题3和4是整个编译原理的关键,所以先说问题3,4。假设c++在编译时,把main.cpp编译成main.obj,array.cpp编译成array.obj。
问题3,4:
第一种hpp写法,编译器知道模板array<int,SIZE>,array::set_elem(int, constT& ),array::get_elem(inti) const
array::operatorint*()的定义,所以能够具现化,main.obj的符号导出表中就有这些符号的地址,于是就不存在链接问题,所以能运行。
第二种声明和实现(定义)分离的方式,编译器在array.h文件中看到了这些模板类和函数的声明,但没有模板的定义,这样编译器就不能创建类型array<int,SIZE>,array::set_elem(int, constT& ),array::get_elem(inti) const
array::operatorT*(),即无法具现化这些符号。但这时并不出错,因为编译器认为模板定义在其它文件中,就把问题留给链接程序处理,希望它能够在其他.obj里面找到的实现体,在本例中就是array.obj(详细可参考c++编译过程)
编译array.cpp时编译器可以解析模板定义并检查语法,但不能生成成员函数的代码,因为要生成代码,需要知道模板参数,即需要一个类型,而不是模板本身。array.cpp中有所有模板函数的实现,但这不是具现,这种实现但不会产生二进制代码。这样在main.obj和array.obj中都没有array<int,SIZE>,array::set_elem(int, constT& ),array::get_elem(inti) const,array::operatorint*()这些符号的具体(实现),即没有它们的二进制代码,所以链接器会报错。
问题1,2,5:
模板的实例化过程是迟钝的,只有需要用的时候(调用 ,或定义)才会去实例化它的定义。
所以当array<int,SIZE>::intArray.print_array(int)不被调用时,编译器不会去检查它是还被实现或具现化。当调用时
编译器发现它没有实现这时候才会报错。
- C++ 中Template 类、函数的编译过程
- c的编译过程
- C的编译过程
- C语言中函数的调用过程
- C/C++:在编译的过程中动态指定宏
- C++,template,类模板和函数模板
- C++template--函数模版
- template函数和template类
- C++Template头文件和定义分开编译的问题
- C++Template头文件和定义分开编译的问题
- C/C++的编译过程中到底发生了什么?
- C程序的编译过程
- C程序的编译过程
- C程序的编译过程
- C程序的编译过程
- c程序的编译过程
- C语言编译的过程
- C语言的编译过程
- ROS中找并编译已存在的Package
- RSA加密与解密
- C++ 中宏(macro)#,##,和...(可变参数宏variadic macros)
- Ubuntu 下关闭/启用触摸板
- expandableListView嵌套GridView
- C++ 中Template 类、函数的编译过程
- Java Web 中通过request请求头获取客户端真实IP
- 在前后端分离的项目中,后台使用shiro框架时,怎样使用它的会话管理系统(session),从而实现权限控制
- 转:Windows文件关联和VC实现
- Loaders 的使用,结合Fragments
- Skill: TightVNC Server: 重置密码
- 【线程】--基础知识
- Druid:一个用于大数据实时处理的开源分布式系统
- 交通银行闪退问题