泛型编程:编写与类型无关的通用代码,是代码复用的一种手段。模板是泛型编程的基础。
先来实现一个支持各种类型的交换函数 Swap
函数模板
函数模板并没有类型,在使用的时候被参数化,更据实参类型产生函数特定类型的版本;
template<typename T1, typename T2,…,typename Tn>
返回值类型 函数名(参数列表){}
template<typename T>
void Swap(T& left, T& right)
{
T temp = left;
left = right;
right = temp;
}
有一点注意的事项:typename是用来定义模板参数关键字,也可以使用class(切记:不能使用struct代替class)
template<class T>
//class / typename 没啥区别
T Add(T left, T right)
{
//查看 T 的类型
cout << typeid(T).name() << endl;
return left + right;
}
int main()
{
Add(10, 20);
Add(10.0,20.0);
//该语句无法通过编译,由于编译器不确定推演出来的类型,
//所以还必须在模板里加一个参数;
Add(10,20.0);
return 0;
}
函数模板的实例化
编译器在编译阶段,要根据实参的类型来确认具体生成什么类型的代码;用不同类型的参数使用函数模板时,称为函数模板的实例化
隐式实例化 VS 显式实例化
-
隐式实例化:没有明确给出模板参数的实际类型,编译器根据实参推演模板参数的实际类型,如果发现推演结果与类型参数不匹配,编译器报错;
Add(10, 20); Add(10.0,20.0); Add(10,(int)20.0)
-
显式实例化:在函数名后的<>中指定模板参数的实际类型,明确指定模板参数列表中的实际类型,直接生成代码,在调用时如果发现类型不匹配会尝试进行类型转换。
Add<int>(10.20.0);
类模板
类模板实例化与函数模板实例化不同,类模板实例化需要在类模板名字后跟<>,然后将实例化的类型放在 <> 中即可,类模板名字不是真正的类,而实例化的结果才是真正的类。
#include <iostream>
#include <stdlib.h>
#include <assert.h>
using namespace std;
//typedef int T;
template<class T>
class SeqList
{
public:
SeqList(size_t capacity = 10)
:_array (new T [capacity])
,_capacity(capacity)
,_size(0)
{}
void PushBack(const T& data);
void PopBack()
{
--_size;
}
size_t Size()const
{
return _size;
}
size_t Capacity()const
{
return _capacity;
}
bool Empty()const
{
return _size == 0;
}
//[] :下标运算符重载
T& operator[](size_t index)
{
assert(index < _size);
return _array[index];
}
const T& operator[](size_t index)const
{
assert(index < _size);
return _array[index];
}
~SeqList()
{
if (_array)
{
delete[] _array;
_array = nullptr;
_capacity = 0;
_size = 0;
}
}
protected:
T* _array;
size_t _capacity;
size_t _size;
};
template<class T>
//SeqList 不是具体的类,是编译器根据被实例化的类型生成具体类的模具
//SeqList<int>才是类
void SeqList<T>::PushBack(const T& data)
{
//CheckCapacity
_array[_size++] = data;
}
int main()
{
//汇编名字为 SeqList<int>::SeqList<int>
SeqList<int> s1;
s1.PushBack(1);
s1.PushBack(2);
s1.PushBack(3);
cout << s1[0] << endl;
//汇编名字为 SeqList<int>::SeqList<int>
SeqList<double> s2;
system("pause");
return 0;
}
C++ 类模板的分离式编译
未完待续…