第十二节,模板
1,模板定义:
若一个程序的功能是对某种特定的数据类型进行处理,则将所处理的数据类型说明为参数,就可以把这个程序改写为模板。 C++ 程序由类和函数组成,
所以 C++ 的模板也分为类模板和函数模板。
上面这个定义有点官方的味道,我自己的理解,其实模板也可以顾名思义,就是一个“模板”,将很多相似的东西模板化使其归为同一类,这样可以大大的简化代码量,而且使用也比较方便。
2,模板函数
既然模板有函数模板和类模板,那么我们就分开说这两个模板,首先先说简单点的-----函数模板。
函数模板定义,我在网上看到一个更好的对模板的总结,就顺手借点共享给大家,他是这样说的:
函数模板的一般定义形式: template < 类型形式参数表 > 返回类型 FunctionName( 形式参数表 ) { // 函数定义体 }
说明:
⒈ < 类型形式参数表 > 可以包含基本数据类型,也可以包含类类型。若是类类型,则须加前缀 class 。
⒉这样的函数模板定义不是一个实实在在的函数,编译系统不为其产生任何执行代码。该定义只是对函数的描述,表示它每次能单独处理在类型形式参数表中说明的数据类型。
⒊当编译系统发现有一个函数调用: FunctionName( 实在参数表 ); 将根据实在参数表中的类型,确认是否匹配函数模板中对应的形式参数表,然后生成一个重载函数。该重载函数的定义体和函数模板的函数定义体相同,而形式参数表的类型则以实在参数表的实际类型为依据。该重载函数称为模板函数。
4,函数模板与模板函数的区别:函数模板是模板的定义,定义中用到通用类型参数。模板函数是实实在在的函数定义,它由编译系统在碰见具体的函数调用时所生成,具有程序代码。
说了这么多理论的东西,下面看看怎么用代码实现模板函数:
//函数模板,比较两个数的大小 template <class T> T max(T x,T y) { return (x>y)?x:y; }; int main(int argc, const char * argv[]) { int a = 10,b = 20; int result = max(a, b); std::cout<<result; double c = 1.001,d = 3.0001; double result1 = max(c, d); std::cout<<"\n"<<result1; return 0; }
这是一个简单的模板函数,以及模板函数的调用。
3,类模板
首先还是先说说类模板的定义。
一个类模板可以让用户为类定义一种模式,使得类中的某些数据成员,某些成员函数的参数,某些成员函数的返回值,能取任意类型。
定义一个类模板,一般由两方面的内容
(1)首先要定义类, 其格式为
template<class T> //声明一个模板 class name { //....类体 }
name为类名,在类定义体中如采用数据类型的成员, 函数参数的前面需加上T。例如:
template<class T> class vector { T * data; int size; pulic: vetor(int); T&operator[](int); //... };
(2)在类定义体外定义成员函数时, 若此成员函数中有模板参数存在, 则需在函数体外进行模板声明,并且在函数名前的类名后缀上“”.例如:
template<class T> vector::vector(int i) { //.... } template<class T> T&vector::operator[](int i) { //.... }
(3),上面的例子能够加深对定义的理解,下面这个例子是从定义到使用类模板的,值得看一下:
//写一个类模板 template <class T> class list { struct Node { Node *pNext; T *pT; }; Node *pFirst; public: list(); void add(T &); ~list(); }; template <class T> list<T>::list() { pFirst = 0; } template <class T> void list<T>::add(T &t) { Node * temp = new Node; temp->pT = &t; temp->pNext = pFirst; pFirst = temp; } template <class T> list<T>::~list<T>() { std::cout<<"\ndelete"; } int main(int argc, const char * argv[]) { list<int> myTest; int x = 55; myTest.add(x); return 0; }
注意类模板的使用,以及在类外定义类成员函数的格式。
4,模板的优势和劣势
说明:【本段文字是借鉴别人的】
使用模板有很多原因,最主要的为了得到通用编程的优点。国际标准化组织(ISO)为C++建立了C++标准库,该标准库功能强大,这证明了模板的重要性。库中涉及算法和容器的部分组成了标准模板库(简称STL)。由于模板的可重用性和可扩展性,你可以利用STL来实现效率很高的代码。
但是模板也有一些不太为人知的缺点。首先,由于C++没有二进制实时扩展性,所以模板不能像库那样被广泛使用。模板的数据类型只能在编译时才能被确定。因此,所有用基于模板算法的实现必须包含在整个设计的头文件中。通过分析标准模板库(STL)的头文件,你可以很清楚的认识到这一点。
另外,由于模板只是最近加入C++标准中,所以有些C++编译器还不支持模板,当使用这些编译器时编译含有模板的代码时就会发生不兼容问题。例如,Mozilla浏览器开发组之所以没有使用模板就是因为交叉平台会导致模板的不兼容。同样的,如果当开发者需要跨越好几个平台而有的平台可能只有老的C++编译器的时候,使用模板也是不明智的。
即使到现在,模板的一些高级特性,例如局部特殊化和特殊化顺序在不同的C++标准实现中也还是不统一的。
尽管如此,结合STL使用模板还是可以大大减少开发时间。模板可以把用同一个算法去适用于不同类型数据,在编译时确定具体的数据类型。
比方说,假设你希望实现一个诸如TCP/IP堆栈所用的开窗重排序机制。这个机制可用于IP数据报和其它数据报格式。通过使用模板后,开窗重排序机制就像流控制那样,无须随所处理数据格式而改变。