C++ 模板

来源:互联网 发布:尼采著作全集 知乎 编辑:程序博客网 时间:2024/06/01 12:26

按照WHAT, WHY, HOW的思路学习。
1. 什么是C++模板?
答:模板就是实现代码重用机制的一种工具。它实现了将类型参数化,就是将类型定义为参数,实现了真正的代码可重用性。模板分为两大类:函数模板和类模板。由于类模板包含类型参数,所以类模板又称作参数化的类。如果说类是对象的抽象,抽象是类的实例;那么可以说类模板是类的抽象,而类是类模板的实例。利用类模板可以建立各种数据类型的类。
2.为什么要引入模板机制呢?
答:为了实现代码重用,避免或者减少做重复性的工作,以及避免因重载函数定义不全面引起的调用错误等。
3.如何使用(实现)?
(1)函数模板的形式:

Template <class或者也可以用typename T>//函数(类)模板的声明返回类型 函数名(形参表)//函数模板的定义/实现{  //函数定义体}

说明:
①template 是声明模板的关键字;class可以被typename代替;T是虚拟类型参数,可以被任何字母,字符串或者数字代替。
②当模板类和重载函数一起使用时,会首先考虑重载函数,其次是模板类,再没有的话会考虑类型转换(可能会不精确)。
测试实例:

//main.cpp#include <iostream>using std::cout;using std::endl;//声明一个函数模板,用来比较输入的两个相同数据类型参数的大小,class也可以被typename代替//T可以被任意字母或者数字代替template <typename T>T max(T x, T y){    return (x > y) ? x : y;}int main(){    int n1 = 2, n2 = 10;    float d1 = 1.5, d2 = 5.6;    cout << "Integer result is:" << max(n1, n2) << endl;    cout << "Real result is:" << max(d1, d2) << endl;    return 0;}

(2)模板类

template <class 类型参数名>//声明模板类class 具体类型参数名 //定义具体类{   //...}

举例:
比如在未使用模板类之前:要对两个整数作比较:

class Compare_integer{public :   Compare(int a,int b)   {      x=a;      y=b;   }   int max( )   {      return (x>y)?x:y;   }   int min( )   {     return (x<y)?x:y;   }private :   int x,y;};

如果你又想对double类型的数据作比较呢,就得重新定义一个新的类来实现:

class Compare_double{public :   Compare(double a,double b)   {      x=a;      y=b;   }   double max()   {      return (x>y)?x:y;   }   double min()   {      return (x<y)?x:y;   }private :   double x,y;}

这样就会比较麻烦。做的重复性的工作很多,使用了模板机制以后就可以减少这些问题。可以声明一个通用的类模板,它可以有一个或多个虚拟的类型参数,比如对上面两个类可以综合写出以下的类模板:

template <class numtype>class Compare{public :   Compare(numtype a,numtype b)   {     x=a;     y=b;   }   numtype max()   {     return (x>y)?x:y;   }   numtype min()   {     return (x<y)?x:y;   }private :   numtype x,y;}

将这个类模板和前面的两个类作比较,会发现:
1>多出了一行template 即声明类模板时要先加上一行template
2>原有的类型名int换成虚拟类型参数名numtype.这样在建立类对象时,如果将实际类型指定为int型,编译系统就会用int取代所有的numtype,如果指定为double型,就用double取代所有的numtype。这样就能实现“一类多用”。

在声明了一个类模板之后,如何使用它,将它变成一个实际的类呢?
回想一般的定义一个对象的方法:

Compare_double cmp(2.35.8);//Compare_double是已经声明的类

用类模板来定义对象的方法和上面的方法类似,但是不能直接那么写。Compare是一个类模板名,而不是一个具体类;numtype是一个虚拟类型,而不是一个具体类型;因此无法用它去定义一个对象。而必须用实际的类型名取代虚拟类型,具体做法:

Compare<double> cmp(2.3, 5.8);

即在类模板名之后的尖括号内指定实际的类型名,在进行编译时,编译系统就用double取代类模板中的类型参数numtype,这样就把类模板具体化了,或者说实例化了。这时Compare就相当于前面介绍的Compare_double类。
注意:前面的类模板中的成员函数是在类模板内定义的,如果改为在类模板外定义,则不能使用一般的定义类成员函数的方法:

numtype Compare::max(){...}

而应该写成类模板的形式:

template <class numtype>numtype Compare<numtype>::max(){   return (x>y)?x:y;}

总结上面的学习,可以这样声明和使用类模板:
1)先写出一个实际的类。其语义明确,含义清楚。一般不会错。
2)将该类中准备改变的类型名(比如Int要改为char、double等)改为一个自己指定的虚拟类型名(比如上面例子中的numtype)。
3)在类的声明前加一行:
template 。
4)使用类模板定义对象时使用如下形式:

类模板名<实际类型名> 对象名;类模板名<实际类型名> 对象名(实参列表);

5)如果在类模板之外定义成员函数,应该写成类模板形式:

template <class 虚拟参数类型>

函数类型 类模板名<虚拟参数类型>::成员函数名(函数形参列表){…}

注意:
1)类模板的类型参数可以有一个或者多个,每个类型前面都必须加class,如:

template <class T1,class T2>class someclass{…};

在定义对象名时,分别带入实际的类型名,比如:

someclass<int, char> Obj;

2)和使用普通类一样,在使用模板类时一定要注意其作用域。
3)模板也可以有层次,一个类模板可以作为基类,可以派生出派生模板类。

转自:http://blog.chinaunix.net/uid-27177626-id-3939006.html

0 0