- 泛型编程
- 函数模板
- 函数模板的定义
- 函数模板的实例化
- 模板参数的匹配原则
- 类模板
- 类模板的定义
- 类模板是实例化
泛型编程:编写与类型无关的通用代码,是代码复用的一种手段。模板是泛型编程的基础
为了支持各种类型的两个数据的交换,我们不得不写出多个函数。比如之前写的swap函数:
void Swap(int& a, int& b)
{
int tmp = a;
a = b;
b = tmp;
}
void Swap(double& a, double& b)
{
double tmp = a;
a = b;
b = tmp;
}
void Swap(char& a, char& b)
{
char tmp = a;
a = b;
b = tmp;
}
它们构成函数重载,但是代码复用率低,一旦出现新的类型,就需要用户自己添加相应的函数。代码维护性低,一但发现错误,所有函数都要一起改。
我们能否只写一个函数模板,需要什么类型的函数直接让编译器自己往里面填好了生成出来呢?
答案是可以的,我们称这种方法叫泛型编程
函数模板模板是泛型编程的基础,要用到的关键字:template
函数模板的定义template返回值类型 函数名(参数列表) { }
:typename也可以写成class,当前的角度,用这两个关键字没有区别,T是模板参数,是我们定义函数模板要用的类型名,可以自己随别取
例1:
templatevoid Swap(T& a, T& b) { T tmp = a; a = b; b = tmp; }
模板的声明必须带上模板参数:
//例1的声明: templatevoid Swap(T& a, T& b)
模板不支持声明和定义分离到两个文件。一般是要放到一个文件中,有些地方会把文件命名成xxx.hpp,寓意头文件和定义实现内容合并在一起。
函数模板的实例化调用Swap函数:
:传入不同类型的参数,编译器会按照模板生成不同的函数来调用。
另外,C++库里面有swap函数,我们以后也不用自己实现了
函数模板显式实例化:
如果你写得函数模板无法通过传参来推导类型,就必须手动指定:
调用时在函数模板名后面跟<>,<>内是我们自己指定的类型。
templateT* func(int c) //无法通过传参推导T的类型 { return newT[n]; } int main() { int* p1 = func (10); double* p2 = func (10); return 0; }
再看下面的例子:
templateT Add(const T& a, const T& b) { return a + b; } int main() { int a = 10; double d = 9.8; Add(a, d);//此处报错:没有与参数列表匹配的 函数模板 "Add" 实例 return 0; }
:传入的两个参数的类型不同,T的类型无法确认,此时也可以手动指定成Add
int Add(int a, int b) //专门处理int类型的函数
{
return a + b;
}
template //通用的函数模板
T Add(const T& a, const T& b)
{
return a + b;
}
int main()
{
int a = 1, b = 2;
Add(a, b);
return 0;
}
传入int类型的数据,会优先调用哪个函数呢?
通过调试发现,编译器调用的是专门处理int类型的函数,而没有去用模板实例化生成的。
如果手动指定类型Add
templateclass 类模板名 { };
例:
template类模板是实例化class Stack { public: Stack(int capacity = 0) { _a = new T[capacity]; _capacity = capacity; _top = 0; } ~Stack() { delete[] _a; _capacity = 0; _top = 0; } //... private: T* _a; int _top; int _capacity; };
类不像函数,函数模板可以根据传参去推导要替换的类型,而类模板没有。
类模板的实例化需要在类模板名后面跟<>,<>内的是我们自己指定的类型。
int main()
{
Stack st1;
Stack st2;
return 0;
}
模板参数也支持给缺省参数,比如template


模板的初步了解 [C++](8)模板的初步了解](http://www.mshxw.com/aiimages/31/993655.png)
