C++学习笔记24-2 类模板
2014-09-16 09:15
295 查看
C++ C++中的类模板 中的类模板
― 提供一种特殊的类以相同的行为处理不同的类型
― 在类声明前使用template进行标识
― <typename T> 用于说明类中使用的泛指类型 用于说明类中使用的泛指类型 T
声明的泛指类型 T TT T 可用于声明成员变量和成员函数
编译器对类模板的处理方式和函数模板相同
― 编译器从类模板通过具体类型产生不同的类
― 编译器在声明的地方对类模板代码本身进行编译
― 编译器在使用的地方对参数替换后的代码进行编译
使用具体类型定义对象:
类模板的工程应用
1:由于类模板的编译机制不同, 所以不能像普通类一样分开实现后, 在使用时只包含头文件 在使用时只包含头文件
2:在工程实践上, , 一般会把类模板的定义直接放到头文件中!!
3:只有被调用的类模板成员函数才会被编译器生成可执行代码!!
也就是说模板类不支持分离编译:
首先,C++标准中提到,一个编译单元[translation unit]是指一个.cpp文件以及它所include的所有.h文件,.h文件里的代码将会被扩展
到包含它的.cpp文件里,然后编译器编译该.cpp文件为一个.obj文件,后者拥有PE即windows可执行文件]文件格式,并且本身包含的
就已经是二进制码,但是,不一定能够执行,因为并不保证其中一定有main函数。当编译器将一个工程里的所有.cpp文件以分离的方
式编译完毕后,再由连接器(linker)进行连接成为一个.exe文件。
然而,对于模板,你知道,模板函数的代码其实并不能直接编译成二进制代码,其中要有一个“具现化”的过程。
类模板的工程应用
― 在模板类外部定义成员函数的实现时, 需要加上 template<typename T> 的声明 的声明
对于类模板不支持分离编译。在工程当中的解决办法
test.h不变
将test.cpp 改为 test.hpp (里面包含 test.h)
在main.cpp当中 包含test.hpp(#include "test.hpp")
― 提供一种特殊的类以相同的行为处理不同的类型
― 在类声明前使用template进行标识
― <typename T> 用于说明类中使用的泛指类型 用于说明类中使用的泛指类型 T
template <typename T> class Operator { public: T add(T a, T b) { return a+b; } T minus(T a, T b) { return a- b; } };
声明的泛指类型 T TT T 可用于声明成员变量和成员函数
编译器对类模板的处理方式和函数模板相同
― 编译器从类模板通过具体类型产生不同的类
― 编译器在声明的地方对类模板代码本身进行编译
― 编译器在使用的地方对参数替换后的代码进行编译
使用具体类型定义对象:
Operator<int> op1; Operator<double> op2; cout<<op1.add(200,8)<<endl; cout<<op2.minus(20.77,9.098)<<endl;
类模板的工程应用
1:由于类模板的编译机制不同, 所以不能像普通类一样分开实现后, 在使用时只包含头文件 在使用时只包含头文件
2:在工程实践上, , 一般会把类模板的定义直接放到头文件中!!
3:只有被调用的类模板成员函数才会被编译器生成可执行代码!!
也就是说模板类不支持分离编译:
首先,C++标准中提到,一个编译单元[translation unit]是指一个.cpp文件以及它所include的所有.h文件,.h文件里的代码将会被扩展
到包含它的.cpp文件里,然后编译器编译该.cpp文件为一个.obj文件,后者拥有PE即windows可执行文件]文件格式,并且本身包含的
就已经是二进制码,但是,不一定能够执行,因为并不保证其中一定有main函数。当编译器将一个工程里的所有.cpp文件以分离的方
式编译完毕后,再由连接器(linker)进行连接成为一个.exe文件。
然而,对于模板,你知道,模板函数的代码其实并不能直接编译成二进制代码,其中要有一个“具现化”的过程。
#include <iostream> using namespace std; template<class T> void f(T t) { } int main() { f(10);//编译器在这里决定给f一个f<int>的具体 /* 也就是说,如果你在main.cpp文件中没有调用过f,f也就得不到具现,从而main.obj中也就没有关于f的任意一行二进制代码!!如果你这样调用了: f(10); //f<int>得以具现化出来 f(10.0); //f<double>得以具现化出来 这样main.obj中也就有了f<int>,f<double>两个函数的二进制代码段。以此类推 然而具现化要求编译器知道模板的定义,不是吗? */ return 0; }
看下面的例子:[将模板和它的实现分离] //-------------test.h----------------// template<class T> class A { public: void f(); //这里只是个声明 }; //---------------test.cpp-------------// #include”test.h” template<class T> void A<T>::f() //模板的实现,但注意:不是具现 { …//do something } //---------------main.cpp---------------// #include”test.h” int main() { A<int> a; a.f(); //编译器在这里并不知道A<int>::f的定义,因为它不在test.h里面 //于是编译器只好寄希望于连接器,希望它能够在其他.obj里面找到 //A<int>::f的实现体,在本例中就是test.obj,然而,后者中真有A<int>::f的 //二进制代码吗?NO!!!因为C++标准明确表示,当一个模板不被用到的时 //侯它就不该被具现出来,test.cpp中用到了A<int>::f了吗?没有!!所以实 //际上test.cpp编译出来的test.obj文件中关于A::f的一行二进制代码也没有 //于是连接器就傻眼了,只好给出一个连接错误 //但是,如果在test.cpp中写一个函数,其中调用A<int>::f,则编译器会将其//具现出来,因为在这个点上[test.cpp中],编译器知道模 板的定义,所以能够具现化,于是,test.obj的符号导出表中就有了A<int>::f这个符号的地址,于是连接器就能够完成任务。 }
类模板的工程应用
― 在模板类外部定义成员函数的实现时, 需要加上 template<typename T> 的声明 的声明
对于类模板不支持分离编译。在工程当中的解决办法
test.h不变
将test.cpp 改为 test.hpp (里面包含 test.h)
在main.cpp当中 包含test.hpp(#include "test.hpp")
相关文章推荐
- C++学习笔记24 函数模板
- 金庸小说考试之模板方法模式学习笔记[C++版]
- C++ primer第二次阅读学习笔记(第16章:模板与泛型编程) .
- c++ 模板学习笔记:类模板和函数模板实现pair(权哥)
- c++学习笔记之成员模板
- c++学习笔记(15.类模板)
- 设计模式C++学习笔记之九(Template Method模板方法模式)
- C++学习笔记十六-模板和泛型编程(一)
- c++学习笔记(16.STL模板库简介)
- c++ 模板学习笔记:用数组和类模板模拟通用栈(权哥)
- c++学习笔记之类模板中的友元声明
- Effective C++ 学习笔记(24)
- C++学习笔记_9:类模板
- C++学习笔记十六-模板和泛型编程(二)
- c++ 模板学习笔记:函数模板实现数组通用排序和遍历打印(权哥)
- c++学习笔记(模板)(一)
- C++学习笔记之模板
- C++学习笔记十六-模板和泛型编程(一)
- c++模板 学习笔记
- c++学习笔记(14.函数模板)