模板函数与模板类
模板
模板是泛型编程的基础。所谓泛型编程就是编写与类型⽆关的逻辑代码,是⼀种复⽤的⽅式。
模板分为模板函数和模板类。
1.模板函数
假设现在要实现一个比较数是否相等的重载函数,在以前都要写不同类型的函数,例子如下:
bool IsEqual (int left, int right)
{
return left == right;
}
bool IsEqual (const string& left , const string& right)
{
return left == right;
}
以上是比较了两个整型和两个字符型的函数,这样进行了重载,但是不能比较其他的类型的函数,若想比较其他的类型,则需要重新再写别的函数,这些重复性的工作我们都可以用模板函数进行处理。 函数模板格式:
template <class 形参名1, class 形参名2, class 形参名n>
返回类型 函数名(参数列表)
{...}
模板形参的定义既可以使⽤class,也可以使⽤typename,含义是相同的。
现在要解决比较两个数的函数就可以用模板函数来解决,代码如下:
template<typename T>
bool IsEqual (const T& left , const T& right )
{
return left == right;
}
void test1 ()
{
string s1 ("s1"), s2("s2" );
cout<<IsEqual (s1, s2)<<endl ;
cout<<IsEqual (1,1)<<endl;
}
模板函数就是自己写一份与类型无关的代码,编译器自动通过调用时进行推演,推演出适合整型比较的函数和适合字符型比较的函数,这个过程叫做模板函数的实例化。 具体如下图所示:
在这个过程中,当运行到IsEqual(s1,s2)时,编译器根据传递的参数自动推演出模板形参的类型,从而得出右侧第二个函数,进而调用推演出的函数。
同时,在汇编语言中也可以清晰地看到对于不同参数类型的函数,编译器推演出的函数类型也不相同。
以下是汇编角度看模板函数的推演:
注意:
当出现调用时模板参数不匹配时,需要显示实例化;
具体如下:
template <typename T>
bool IsEqual (const T& left , const T& right )
{
return left == right;
}
void test1 ()
{
cout<<IsEqual (1,1)<<endl;
//cout<<IsEqual(1,1.2)<<endl; // 模板参数不匹配
cout<<IsEqual<int>(1,1.2)<< endl; // 显⽰实例化
cout<<IsEqual<double>(1,1.2)<< endl; // 显⽰实例化
}
在test1()函数,注释的这句代码中有IsEqual(1,1.2),这就是模板参数不匹配,从而需要进行处理,修改为: IsEqual<int>(1,1.2);或修改成如下代码:
template <typename T1, typename T2>
bool IsEqual (const T1& left , const T2& right)
{
return left == right;
}
void test1 ()
{
cout<<IsEqual(1,1)<<endl;
cout<<IsEqual<int>(1,1)<< endl;
cout<<IsEqual(1,1.2)<<endl;
}
从而达到不同类型也可以进行比较。 2.模板类
模板类的格式:
template<class 形参名1, class 形参名2, ...class 形参名n>
class 类名
{ ... };
以实现动态顺序表为例:
template<typename T>
class SeqList
{
public :
SeqList();
~ SeqList();
private :
int _size ;
int _capacity ;
T* _data ;
};
template <typename T>
SeqList <T>:: SeqList()
: _size(0)
, _capacity(10)
, _data(new T[ _capacity])
{}
template <typename T>
SeqList <T>::~ SeqList()
{
delete [] _data ;
}
void test1 ()
{
SeqList<int > sl1;
SeqList<double > sl2;
}
其中, SeqList为类名,SeqList<T>为类型名,这是使用模板类的不同之处。 同时,在运行时,编译器推演过程及模板类的实例化如下图所示:
当测试函数中创建两个不同的顺序表sl1,sl2,时,整型的顺序表sl1,传递参数后,编译器通过传递的参数进行推演,得到整型的顺序表结构,同理可得,双精度浮点型的顺序表sl2也通过编译器推演的到相应的结构。