C++ 模板
0.前言
模板是一种通用的描述机制,当使用模板时,允许使用通用类型来定义函数或类。通用类型可被具体类型(如int,double甚至是用户自定义类型)来代替。模板引入了一个全新的编程思维方式,称为“泛型编程”或者“通用编程”。
1.函数模板
1)函数模板声明形式如下:
template <class(或typename) A,...,int B (常数)> 返回类型 函数名(参数列表) { //函数体 }
class用于定义类,在模板引入c++后,最初定义模板的方法为:template<class T>,这里class关键字表明T是一个类型,后来为了避免class在这两个地方的使用可能给人带来混淆,所以引入了typename这个关键字,它的作用同class一样表明后面的符号为一个类型。
2)函数模板的使用
函数模板定义形式如下:
template <class T1[, class T2, ......]> 函数原型;
3)函数模板实例化
3.1)隐式实例化:
1 /*************************main.c********************/ 2 #include <iostream.h> 3 using namespace std; 4 template<class Ex> 5 Ex Greater(Ex x,Ex y); 6 7 int main() 8 { 9 int inx=1;iny=2; 10 cout<<Greater(inx,iny)<<endl; //实参为int类型,生产int型模板函数,并对第二个进行实参检查 11 return 0; 12 } 13 14 template<class Ex> 15 Ex Grearer(Ex x,Ex y) 16 { 17 return x>y?x:y; 18 }
输出结果如下为2;
3.2)显示实例化标准格式如下:
template 返回类型 函数名<类型实参表> (函数参数表)
1 /*************************main.c********************/ 2 #include <iostream.h> 3 using namespace std; 4 template<class Ex> 5 Ex Greater(Ex x,Ex y); 6 7 template int Greater<int> (int,int); 8 9 int main() 10 { 11 int inx=1;iny=2; 12 cout<<Greater(inx,iny)<<endl; //调用实例化模板函数 13 return 0; 14 } 15 16 template<class Ex> 17 Ex Grearer(Ex x,Ex y) 18 { 19 return x>y?x:y; 20 }
3.3)利用特化可以解决某些类型在函数中的特殊操作,特化的基本格式如下:
template<> 返回类型 函数名[(类型实参表)](函数参数表)
其中类型实参表可以省略,有后续的函数参数表来指定。
1 /*************************main.c********************/ 2 #include <iostream.h> 3 using namespace std; 4 template<class Ex> 5 Ex Greater(Ex x,Ex y); 6 7 template<> double Greater<double>(double,double); //特化声明 8 9 int main() 10 { 11 int inx=1;iny=2; 12 double dbx = 3.0,dby = 2.9; 13 cout<<Greater(inx,iny)<<endl; //隐式实例化 14 cout<<Greater(dbx,dby)<<endl; //优先调用特化函数 15 return 0; 16 } 17 18 template<class Ex> 19 Ex Grearer(Ex x,Ex y) 20 { 21 return x>y?x:y; 22 } 23 24 template<> double Greater(double x,double y) //特化定义 25 { 26 return x+y; 27 }
输出结果为:
1 2 2 5.9
3.4)优先级和执行顺序
一般函数的执行顺序优先于模板的特化函数,模板的特化函数优先于实例化函数。
更特化的含义体现在“编译器做决定是执行的转换最少”,c++遵循部分排序规则来选择最优化模板函数。
1 template<class T> void f(T) {} #1 2 template<class T> void f(T*) {} #2 3 template<class T> void f(const T*) {} #3 4 template<class T> void g(T) {} #4 5 template<class T> void g(T&) {} #5 6 7 int main() 8 { 9 const int *p; 10 f(p); 11 int q; 12 //g(q); 13 }
模板#2比模板1更特化,模板3比模板2更特化,因此f(p)调用#3。然而模板#4和#5没有谁比谁更特化,因此g(q)会带来二义性错误。
2.类模板
1)类模板的定义
template<class 模板参数表> class 类名{ // 类定义 };
2)类模板实例化
2.1)隐式实例化
首先定义类模板:
1 template <class T,int num> 2 class Stack 3 { 4 private: 5 T sz[num]; 6 int point; 7 public: 8 Stack(); 9 ... 10 } 11 12 template<class T,int num> 13 Stack<T,num>::Stack() 14 { 15 point = 0; 16 }
然后使用一下语句隐式实例化:
Stack<int,10> st;
下述语句不需要创建对象,编译器不会隐式生成类定义:
Stack<int,10> *ps;
2.2)显示实例化
template class 类名<类型参数表>
2.3)显示特化
template<> class 类名<特殊类型> { 类定义; }
2.4)部分特化
template<class T1 , class T2> class Example { //类定义 }; 部分特化定义为: template<class T2> class Example<int ,T2> { //类定义 }
3)模板的嵌套
3.1)函数成员模板
成员模板不能声明为虚函数。
1 #include <iostream.h> 2 using namespace std; 3 template<class A> 4 class Test 5 { 6 public: 7 template<class B> 8 A f(B); 9 }; 10 11 template<class A> 12 template<class B> 13 A Test<A>::f(B) 14 { 15 return A(B); 16 } 17 18 int main() 19 { 20 Test<int> t; 21 cout<<t.f(3.14)<<endl; 22 return 0; 23 }
输出结果是:3
3.2)对象成员模板
类模板的定义可以放在另一个类中,实例化后的模板对象可以作为另一个类的成员。
1 #include <iostream.h> 2 using namespace std; 3 template<class T> 4 class Outside 5 { 6 public: 7 template<class R> 8 class Inside 9 { 10 private: 11 R r; 12 public: 13 Inside(R r) //类模板的成员函数可以在定义时实现 14 { 15 r = x; 16 } 17 void disp(); 18 }; 19 void disp(); 20 private: 21 Inside<T> t; 22 } ; 23 24 template<class T> 25 template<class R> 26 void Outside<T>::Inside<R>::disp() //类模板的成员函数也可以在定义外实现 27 { 28 cout<<"Inside: "<<Outside<T>::Inside<R>::r<<endl; 29 } 30 31 template<class T> 32 void Outside<T>::disp() 33 { 34 cout<<"Outside:"; 35 t.disp(); 36 } 37 38 int main() 39 { 40 Outside<int>::Inside<double> obin(3.5); //声明Inside类对象 41 obin.disp(); 42 Outside<int> obout(2); //创建Outside对象obout 43 obout.disp(); 44 return 0; 45 }
输出结果如下:
Inside: 3.5 Outside:Inside: 2
4)模板参数
模板可以作为另一个模板的参数类型,形式如下:
template<template <class T1> class T2,class T3,int Num>;
1 #include <iostream> 2 using namespace std; 3 4 template<class T,int num> 5 class Stack 6 { 7 private: 8 T sz[num]; 9 public: 10 int ReturnNum(); 11 }; 12 template<class T1,int num1> 13 int Stack(T1,num1>::ReturnNum() 14 { 15 return num1; 16 } 17 18 template<template<class Type,int NUM> class TypeClass,class T1,int N> 19 void disp() 20 { 21 TypeClass<T1,N> ob; //类模板的隐式实例化,创建对象ob 22 cout<<ob.ReturnNum()<<endl; 23 } 24 25 int main() 26 { 27 disp<Stack,int,8>(); 28 return 0; 29 }
输出结果为:8。