泛型编程是独立于任何特定类型的方式编写代码。模板是泛型编程的基础,模板使程序员能够快速建立具有类型安全的类库集合和函数集合,它的实现,方便了大规模的软件开发。
模板提供通用类型和通用函数,定义中包含template,和一对尖括号<>,尖括号里面是模板参数。模板参数与普通参数的区别在于,模板参数不仅可以传变量和值,还可以传类型。模板参数中定义类型可以使用关键字typename或class(效果一样,有的开发者为区分,函数使用typename,类使用class,实际等同);参数名默认是T,可以为任意字符,效果等同,只是T较常用,默认。
模板应放到头文件中。模板本质上就是一种宏定义。
一. 函数模板
template<typename T>
返回类型 function(形式参数表)
{
//函数定义体
}
template ---- 声明创建模板
typename ---- 表明其后面的符号是一种数据类型,可以用class代替
T ---- 通用数据类型,名称可以替换,通常为大写字母
template <class T>
void myswap(T &a, T &b)
{
T temp = a;
a = b;
b = temp;
}
使用函数模板有两种方式:自动类型推导、显示指定类型
void test01()
{
int a = 10, b = 20;
// myswap(a, b);
myswap<int>(a, b);
cout << "a = " << a << endl;
cout << "b = " << b << endl;
模板的目的是为了提高复用性,将类型参数化。
注:1)自动类型推导,必须推导出一致的数据类型T才可以使用。
2)模板必须要确定出T的数据类型,才可以使用。(比如函数没有参数且不能自动推导出T类型)
template<class T>
void func()
{
cout << "call func" << endl;
}
int main()
{
// func(); // 不能推导出T类型
func<int>();
return 0;
}
普通函数和函数模板区别:
普通函数调用可以发生自动类型转换(隐式类型装换);函数模板调用时如果利用自动类型推导,不会发生隐式类型转换;如果利用显示指定类型的方式,可以发生隐式类型转换。
建议使用显示指定类型的方式,调用函数模板,因为可以自己确定通用类型T。
普通函数与函数模板的调用规则(函数重载时):
1)如果函数模板和普通函数都可以实现,优先调用普通函数;
2)可以通过空模板参数列表来强制调用函数模板;myPrintf<>(a, b);
3)函数模板也可以发生重载;
4)如果函数模板可以产生更好的匹配,优先调用函数模板。
建议在使用模板时,不要提供普通函数(两者不要同时出现)。
模板局限性:自定义类型操作
C++为了解决自定义数据类型的无法正常运行问题,提供模板的重载,为这些特定的类型提供具体化的模板。
#include <iostream>
#include <cstdlib>
#include <unistd.h>
#include <string>
using namespace std;
class Person
{
public:
Person(string name, int age){
this->m_name = name;
this->m_age = age;
}
string m_name;
int m_age;
};
template <class T>
bool myCompare(T &a, T&b)
{
if(a == b){
return true;
} else {
return false;
}
}
// 利用具体Person的版本实现代码,具体化优先调用
template<> bool myCompare(Person &p1, Person &p2)
{
if(p1.m_name == p2.m_name && p1.m_age == p2.m_age){
return true;
} else {
return false;
}
}
void test02()
{
Person p1("Tom", 10);
Person p2("Tom", 10);
cout << myCompare(p1, p2) << endl;
}
int main(int argc, char *argv[])
{
test02();
pause();
return 0;
}
利用具体化的模板可以解决自定义类型的通用化。
学习模板并不是为了能写模板,而是在STL能够运用系统提供的模板。
二. 类模板
template <模板参数表> class 类名{};
template<class T1, class T2>
class 类{
类成员声明;
};
T是占位符类型名称,可以在类被实例化的时候进行指定。您可以使用一个逗号分隔的列表来定义多个泛型数据类型。
在类模板以外定义成员函数
template <模板参数表> 类型名 类名<参数列表>::函数名(参数表)
模板类中的函数都是模板函数。
template <class T> Node<T>::~Node()
{
......
}
参考: