C++模板
1 模板的概念
模板 字面意思和模型相似,造一个东西,总会有一个模型为基础。如果以后有什么改动,也要在模型的基础上改在。 这么想,大家都知道了 c++里模板也一样也是模型,那这个模型有什么用呢 。
例如,我们希望编写一个函数来比较俩个值,并指出第一个值,是小于?还是大于?还是等于,第二个值。在以前,我们可能想要定义多个函数,每个函数比较一种特定的类型的值。我们会写个重载函数:
int compare(const string &v1,const string &v2)
{
if(v1<v2)
return 1;
if(v2<v1)
return -1;
return 0;
}
int compare(const double&v1,const double &v2)
{
if(v1<v2)
return 1;
if(v2<v1)
return -1;
return 0;
}
这两个函数几乎相同,唯一的差异就是参数类型不同,函数体则完全相同。
如果对每种希望比较的类型都不得不重复定义完全一样的函数体,是非常容易出错的 。甚至让人崩溃(在我以前不知道模板的时候)
但是模板出现后,就大大不一样了,很方便,用法也很简单。接下来学习简单的函数模板。
1.1 函数模板
我们可以定义一个通用的函数模板,而不是为每个类型定义一个新函数。一个函数模板就是一个模型一个公式,可以生成特定类型的函数版本。compare模板可以像这样定义。
template <typename T>
int compare (const T &v1 , const T &v2)
{
if(v1<v2)return 1;
if(v2<v1)return -1;
return 0;
}
1.1.1 函数模板的格式:
template <class 形参名,class 形参名,......> 返回类型 函数名(参数列表)
{
函数体
}
其中template和class,没错,他两是一样的。在这里typename 和class没区别
以关键字 template开始,后面跟一个模板参数列表。用< >包围起来。
1.1.2 实例化函数模板
当我们调用一个函数模板时候,编译器 用 函数的实参 来为我们推断 模板的实参类型。比如,我们调用上面的compar时候,编译器就知道自己的模板参数T是什么类型了。
cout << compare(1,0)<<endl; //T为 int类型
实参类型是 int 编译器会推断出模板实参 为 int ,并将它绑定到模板参数 T 上。
接着,编译器根据 他自己推断出的 模板参数 来为我们 实例化一个特定的函数,(就专门为你制定的哦)。
当编译器实例化一个模板时,她会使用实际的模板参数 代替 对应的模板参数 来创建出模板的一个新实例。
例如 :
//实例化出 int comnpare (const int &, const int &)
cout <<compare (1 , 0) << endl; //T 为 int
//实例化出 int compare(const vector<int>&,const //vector<int>&
vector<int> vec{1,2,3},vwc2{4,5,6};
cout <<compare(vec1,vec2)<<endl; // T为 vector<int>
编译器会实例化两个不同的 compare。
1.2 类模板
类模板 是用来生成类的蓝图的,与函数模板不同的地方是,编译器不能为类模板推断模板参数类型。 除非有额外的信息,接下来会说到。
定义类模板
1.2.1、类模板的格式为:
template<class 形参名,class 形参名,…> class 类名
{ ... };
类似函数模板,类模板以关键字 template 开始,后面跟模板参数列表。在类模板及其中的成员,我们将模板参数当做替身,代替使用模板的时候,用户需要提供类型 或 值。
以下是一些例子 大家参考一下。
// ClassTemplate.h
template<typename T1,typename T2>
class myClass{
private:
T1 I;
T2 J;
public:
myClass(T1 a, T2 b);//Constructor
void show();
};
//这是构造函数
//注意这些格式
template <typename T1,typename T2>
myClass<T1,T2>::myClass(T1 a,T2 b):I(a),J(b){}
//这是void show();
template <typename T1,typename T2>
void myClass<T1,T2>::show()
{
cout<<"I="<<I<<", J="<<J<<endl;
}
// Test.cpp
#include<iostream>
#include"ClassTemplate.h"
using std::cout;
using std::endl;
void main()
{
myClass<int,int> class1(3,5);
class1.show();
myClass<int,char> class2(3,"a");
class2.show();
myClass<double,int> class3(2.9,10);
class3.show();
system("PAUSE");
}
1.2.1 类模板和函数模板,都是以template开始,后接模板形参列表组成。模板形参不能为空,一但声明了类模板就可以用类模板的形参名,声明类中的成员变量和成员函数。即可以在类中使用内置类型的地方都可以使用模板形参名来声明。比如
template<class T>
class A {
public:
T a; T b;
T hy(T c, T &d);
};
//在类A中声明了两个类型为T的成员变量a和b,还声明了一个返回类型为T带两个参数类型为T的函数hy。
1.2.3
类模板对象的创建:比如一个模板类A,则使用类模板创建对象的方法为A< i n t > m;在类A后面跟上一个<>尖括号并在里面填上相应的类型,这样的话类A中凡是用到模板形参的地方都会被int 所代替。当类模板有两个模板形参时创建对象的方法为A < int, double > m;类型之间用逗号隔开。
1.2.4
对于类模板,模板形参的类型必须在类名后的尖括号中明确指定。比如A< 2 > m;用这种方法把模板形参设置为int是错误的(编译错误:error C2079: ‘a’ uses undefined class ‘A< int >’),类模板形参不存在实参推演的问题。也就是说不能把整型值2推演为int 型传递给模板形参。要把类模板形参调置为int 型必须这样指定A< int > m。
1.2.5
在类模板外部定义成员函数的方法为:
template<模板形参列表> 函数返回类型 类名<模板形参名>::函数名(参数列表){函数体},
比如有两个模板形参T1,T2的类A中含有一个void h()函数,则定义该函数的语法为:
template<class T1,class T2> void A<T1,T2>::h(){}
注意:当在类外面定义类的成员时template后面的模板形参应与要定义的类的模板形参一致。
1.2.6
再次提醒注意:模板的声明或定义只能在全局,命名空间或类范围内进行。即不能在局部范围,函数内进行,比如不能在main函数中声明或定义一个模板。