现在的位置: 首页 > 综合 > 正文

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

2016年02月04日 ⁄ 综合 ⁄ 共 2015字 ⁄ 字号 评论关闭

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")


抱歉!评论已关闭.