按照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 <class numtype> 即声明类模板时要先加上一行template
2>原有的类型名int换成虚拟类型参数名numtype.这样在建立类对象时,如果将实际类型指定为int型,编译系统就会用int取代所有的numtype,如果指定为double型,就用double取代所有的numtype。这样就能实现“一类多用”。
在声明了一个类模板之后,如何使用它,将它变成一个实际的类呢?
回想一般的定义一个对象的方法:
-
Compare_double cmp(2.3, 5.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.csdn.net/hackbuteer1/article/details/6735704
阅读(20301) | 评论(0) | 转发(7) |