目录
1. 泛型编程
2. 函数模板
3. 类模板
1、泛型编程
什么是泛型编程?
泛型编程是编写与类型无关的通用代码,是代码复用的一种手段,模板是泛型编程的基础。
举个例子来说明一下吧。
利用模板实现两个变量的交换
#include<iostream>
#include<string>
using namespace std;
template <class T>
void Swap(T & x, T & y)
{
T temp = x;
x = y;
y = temp;
cout << x << ' ' << y << endl;
}
int main()
{
int a = 2, b = 3;
double a1 = 1.2, b1 = 9.8;
char a2 = 'a', b2 = 't';
cout << "交换前" << endl;
cout << a << ' ' << b << endl;
cout << a1 << ' ' << b1 << endl;
cout << a2 << ' ' << b2 << endl;
cout << "交换后" << endl;
Swap(a, b);
Swap(a1, b1);
Swap(a2, b2);
system("pause");
return 0;
}
2、函数模板
2.1 函数模板概念
从上边的代码可以看出来,我们只写了一个函数,在测试中,我们要实现3种不同类型的变量的交换。我们给他们统一定了一个T类型(这里的T不是固定 可以随意定义)用此方法来完成交换。这里的交换函数就称为函数模板,它可以实现各种类型变量的交换。
2.2 函数模板格式
template<typename T1, typename T2,......,typename Tn>
返回值类型 函数名(参数列表){}
2.3 函数模板的实例化
用不同类型的参数使用函数模板时,称为函数模板的实例化。模板参数实例化分为:隐式实例化和显式实例 化。
1. 隐式实例化:让编译器根据实参推演模板参数的实际类型
template <class T>
T Add(const T & x, const T& y)
{
return x + y;
}
int main()
{
int a = 10;
double b = 20.0;
cout << Add(a, b) << endl;
system("pause");
return 0;
}
该语句不能通过编译,因为在编译期间,当编译器看到该实例化时,需要推演其实参类型 通过实参a将T推演为int,通过实参b将T推演为double类型,但模板参数列表中只有一个T, 编译器无法确定此处到底该将T确定为int 或者 double类型而报错
注意:在模板中,编译器一般不会进行类型转换操作,因为一旦转化出问题,编译器就需要背黑锅
这种情况有2中解决办法:
1、用户自己强转
cout << Add(a, (int)b) << endl;
2、使用显示实例化
cout << Add<int>(a,b) << endl;
2.5 模板参数的匹配原则
一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这个非模板函数
对于非模板函数和同名函数模板,如果其他条件都相同,在调动时会优先调用非模板函数而不会从该模板产生出一个实例。如果模板可以产生一个具有更好匹配的函数, 那么将选择模板
模板函数不允许自动类型转换,但普通函数可以进行自动类型转换
void Swap(int & x, int & y)
{
int temp = x;
x = y;
y = temp;
cout << x << ' ' << y << endl;
}
给第一个代码中加入int 型的交换函数,那么在进行int a ,int b 交换时。系统调用的是那个函数呢?
调式看一下过程。
可以很清晰的看到,调用的是我们新写的int型交换函数。
3、类模板
3.1 类模板的定义格式
template<class T1, class T2, ..., class Tn>
class 类模板名
{
// 类内成员定义
};
template<class T>
class Vector
{
T* m_Data;
size_t m_size;
size_t m_capacity;
public:
Vector(size_t capacity = 10)
: m_Data(new T[capacity])
, m_size(0)
, m_capacity(capacity)
{
}
~Vector();
size_t Size()
{
return m_size;
}
T& operator[](size_t pos)
{
assert(pos < m_size);
return m_Data[pos];
}
};
template <class T>
Vector<T>::~Vector()
{
if (m_Data)
delete[] m_Data;
m_size = m_capacity = 0;
}
注意:类模板中函数放在类外进行定义时,需要加模板参数列表 (如上代码中的析构函数)
3.2 类模板的实例化
类模板实例化与函数模板实例化不同,类模板实例化需要在类模板名字后跟<>,然后将实例化的类型放在<>
中即可,类模板名字不是真正的类,而实例化的结果才是真正的类。
// Vector类名,Vector<int>才是类型
Vector<int> s1;
Vector<double> s2;