C++学习笔记24-2 类模板

来源:互联网 发布:mac shift切换中英文 编辑:程序博客网 时间:2024/06/07 01:57
C++ C++中的类模板 中的类模板
― 提供一种特殊的类以相同的行为处理不同的类型
― 在类声明前使用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")






0 0