学习资源来源于中国MOOC,北大-面向对象程序设计
函数模板
- 定义: 函数模板不是一个实在的函数,编译器不能为其生成可执行代码。定义函数模板后只是一个对函数功能框架的描述,当它具体执行时,将根据传递的实际参数决定其功能(百度定义)
一般形式:
template <class 类型参数1,class 类型参数2,……>
返回值类型 模板名 (形参表) { 函数体 };
示例
在执行过程中,编译器自动生成 void Swap(int & ,int & )函数和//编译器自动生成 void Swap(float & ,float & )函数。
- 函数模板中可以有不止一个类型参数。
template <class T1, class T2> T2
print(T1 arg1, T2 arg2) {
cout<< arg1 << " "<< arg2<<endl;
return arg2;
}
如求数组中最大元素的实现
3. 不通过参数实例化函数模板
直接在函数后加 <类型>
即可。
4. 函数模板可以重载,只要它们的形参表或类型参数表不同即可。
5. 在有多个函数和函数模板名字相同的情况下,编译器如下处理一 条函数调用语句:
- 先找参数完全匹配的普通函数(非由模板实例化而得的函数)。
- 再找参数完全匹配的模板函数。
- 再找实参数经过自动类型转换后能够匹配的普通函数。
- 上面的都找不到,则报错。
- 匹配模板函数时,不进行类型自动转换。
示例map模板
template<class T,class Pred>
void Map(T s, T e, T x, Pred op)
{
for(; s != e; ++s,++x) { *x = op(*s);}
}
int a[5] = {1,2,3,4,5}, b[5]; Map(a,a+5,b,Square); //实例化出以下函数:
void Map(int * s, int * e, int * x, double ( *op)(double))
{
for(; s != e; ++s,++x)
{ *x = op(*s);}
}
其中double ( *op)(double))
第一个double是返回参数类型,第二double是传入参数类型,op是函数指针。
类模板
为了多快好省地定义出一批相似的类,可以定义类模板,然后由类模 板生成不同的类。
类模板: 在定义类的时候,加上一个/多个类型参数。在使用类模板时,指定类型参数应该如何替换成具体类型,编译器据此生成相应的模板类。
一般形式
template <class 类型参数1,class 类型参数2,……> //类型参数表
class 类模板名 {
成员函数和成员变量
};
类模板里成员函数的写法:
template <class 类型参数1,class 类型参数2,……> //类型参数表
返回值类型类模板名<类型参数名列表>::成员函数名(参数表) {
…… }
示例
#include<iostream>
using namespace std;
template <class T1,class T2>
class Pair {
public:
T1 key; //关键字
T2 value; //值
Pair(T1 k,T2 v):key(k),value(v) { };
bool operator < ( const Pair<T1,T2> & p) const;
};
template<class T1,class T2>
bool Pair<T1,T2>::operator < ( const Pair<T1,T2> & p) const //Pair的成员函数 operator <
{
return key < p.key;
}
int main()
{
Pair<string,int> student("Tom",19); //实例化出一个类
cout << student.key << " " << student.value;
return 0;
}
执行效果
编译器由类模板生成类的过程叫类模板的实例化。由类 模板实例化得到的类,叫模板类。
注意同一个类模板的两个模板类是不兼容的。
如下例子所示:
Pair<string,int> * p;
Pair<string,double> a;
p = & a; //wrong
函数模版作为类模板成员
注意类模板的“<类型参数表>”中可以出现非类型参数。
类模板与派生
• 类模板从类模板派生
• 类模板从模板类派生
• 类模板从普通类派生
• 普通类从模板类派生
类模板与友元
• 函数、类、类的成员函数作为类模板的友元
• 函数模板作为类模板的友元
• 函数模板作为类的友元
• 类模板作为类模板的友元
类模板与静态 成员变量