C++ 模版
背景 :
c++ 多态可以大致分为两种:
- 继承(动态的多态)
- 模版(静态的多态)
分类 :
- 函数模版
- 类模版
- 函数模版 :
// 普通函数 void Swap(int & a, int & b) { int tmp = a; a = b ; b = tmp; } // 函数模版 template <class T> void Swap( T & a , T & b) { T tmp = a; a = b; b = tmp; }
这样的好处一眼就能看到 : 兼容 int double 等等的基础类型,不会显得代码冗余,在编译的时候根据我们的定义 实例化对应的函数模版
同时,template<class T1, class T2> 可以实现多种类型的参数
函数模版可以重载 :
// 模板函数 1 template<class T1, class T2> void print(T1 arg1, T2 arg2) { cout<< arg1 << " "<< arg2<<endl; } // 模板函数 2 template<class T> void print(T arg1, T arg2) { cout<< arg1 << " "<< arg2<<endl; } // 模板函数 3 template<class T,class T2> void print(T arg1, T arg2) { cout<< arg1 << " "<< arg2<<endl; }
根据模版参数不同实现函数重载 形参数量不同或者名字不同
函数模版和函数的次数关系
在有多个函数和函数模板名字相同的情况下,编译器如下规则处理一条函数调用语句:
- 先找参数完全匹配的普通函数(非由模板实例化而得的函数);
- 再找参数完全匹配的模板函数;
- 再找实参数经过自动类型转换后能够匹配的普通函数;
- 上面的都找不到,则报错。
模版的特例化:
- 完全特例化
- 部分特例化
类模版
为了更好的定义一系列具有相同功能的类 ,可以定义类模版,由类模版生成不同的类
template<typename T> // 也可使用 template<class T> class A { public : A() {} ~A() {} private: T * _ptr; T count; };
函数模版作为类模版的成员
当函数模板作为类模板的成员函数时,是可以单独写成函数模板的形式,成员函数模板在使用的时候,编译器才会把函数模板根据传入的函数参数进行实例化,例子如下:
/ 类模板 template <class T> class A { public: template<class T2> void Func(T2 t) { cout << t; } // 成员函数模板 }; int main() { A<int> a; a.Func('K'); //成员函数模板 Func被实例化 a.Func("hello"); //成员函数模板 Func再次被实例化 return 0; }
类模版与非类型参数 :
template <class T, int size> class CArray { public: void Print( ) { for( int i = 0;i < size; ++i) cout << array[i] << endl; } private: T array[size]; }; CArray<double,40> a2; CArray<int,50> a3; //a2和a3属于不同的类
类模版与派生
// 基类 - 类模板 template <class T1,class T2> class A { T1 v1; T2 v2; }; // 派生类 - 类模板 template <class T1,class T2> class B:public A<T2,T1> { T1 v3; T2 v4; }; // 派生类 - 类模板 template <class T> class C:public B<T,T> { T v5; }; int main() { B<int,double> obj1; C<int> obj2; return 0; }
类模版从模版类派生
template <class T1,class T2> class A { T1 v1; T2 v2; }; template <class T> class B:public A<int,double> // A<int,double> 模板类 { T v; }; int main() { //自动生成两个模板类 :A<int,double> 和 B<char> B<char> obj1; return 0; }
类模版从普通类继承
// 基类 - 普通类 class A { int v1; }; // 派生类 - 类模板 template <class T> class B:public A // 所有从B实例化得到的类 ,都以A为基类 { T v; }; int main() { B<char> obj1; return 0; }
普通类从模版类派生
template <class T> class A { T v1; }; class B:public A<int> { double v; }; int main() { B obj1; return 0; }
模版的完全特例化和部分特例化
如果一个模版函数是比较数值大小,当我们想进行字符串比较时,就需要对字符串类型做出一个特例,这就是模版的特例 ,可看下面例子
#include<iostream> #include<stdlib.h> #include<string.h> #include<string> #include<unistd.h> using namespace std; template<typename T> class Vector { public: Vector() {cout<<"Vector()"<<endl;} ~Vector() {cout<<"~Vector()"<<endl;} }; // 完全特例化 template<> class Vector<char*> { public: Vector() {cout<<"Vector(char*)"<<endl;} ~Vector() {cout<<"~Vector(char*)"<<endl;} }; // 对指针类型的部分特例化 template<typename Ty> class Vector<Ty *> { public: Vector() {cout<<"Vector(Ty*)"<<endl;} ~Vector() {cout<<"~Vector(Ty*)"<<endl;} }; // 对返回值是指针,参数为两个的部分特例化 template<typename R, typename T1 , typename T2> class Vector<R(*)(T1,T2)> { }; int main() { cout<<endl; return 0; }