一、什么是模板?
照猫画虎,照葫芦画瓢,所谓模板,就是代码的基本结构和内容,但该代码与类型无关,提高代码的复用。模板是泛型编程的基础。模板分为函数模板和类模板。
二、函数模板
1.函数模板的概念:该函数模板与类型无关,根据实参类型产生特定的函数版本
2.格式:
template<typename T1,typename T2,...>
返回值类型 函数名(参数列表){}
template<typename T>
void Swap(T& left, T& right)
{
T tmp = left;
left = right;
right = tmp;
}
3.函数模板并不是具体的函数,传参时编译器会检查实参的类型,然后产生该类型对应的函数,这一过程称为实例化。
隐式实例化:传入参数,编译器自己检测参数类型。如下,Add(a,b)时,实参a,b为int类型,编译器就产生一份对应的int类型的代码,但Add(a,c)时,a的类型时int, c的类型是double,由于模板参数列表中只有一个T,编译器不确定将T转化为int还是double,此时就要自己强制转化或者显示实例化。
显式实例化:在函数名的<>中加上特定类型,如Add<int>(c,d)。若显式实例化类型不匹配,编译器会隐式实例化,失败时报错。
template<typename T>
T Add(const T& left,const T& right)
{
return left + right;
}
void Test()
{
int a = 1, b = 3;
double c = 1.1, d = 3.3;
Add(a, b);//隐式实例化
Add(c, d);
//Add(a, c);不能通过编译,模板中 编译器不会进行类型转换操作
Add(a, (int)c);//
Add<int>(c, d);//4 显式实例化
}
4.优先选择?
如果一个非模板函数和同名函数模板同时存在,若参数类型和非模板函数完全相同,优先调用非模板函数;否则调用模板函数实例化。
int Add(int left, int right)
{
return left + right;
}
template<typename T>
T Add( T& left, T& right)
{
return left + right;
}
void Test()
{
Add(1, 3);//与非模板函数匹配
Add<int>(1, 3);//调用模板函数
Add<int>(1.0, 3.0);//调用模板函数
}
三、类模板
1.template<typename T1,typename T2,...>
class 类模板名
{ ... };
template<typename T>
class Vector
{
public:
Vector(size_t capacity = 10)
:_p(new T(capacity))
,_size(0)
,_capacity(capacity)
{}
~Vector();
void PushBack(const T& data)
{
_p[_size++] = data;
}
void PopBack()
{
--_size;
}
size_t Size()
{
return _size;
}
T& operator[](size_t pos)
{
assert(pos < _size);
return _p[pos];
}
private:
T* _p;
size_t _size;
size_t _capacity;
};
template<typename T>//类模板中的函数在类外定义时要加模板
Vector<T>::~Vector()
{
if (_p)
free(_p);
}
2.类模板的实例化:类名后加<type>,如下Vector<int> ,v1才是一个具体的类。
void Test()
{
Vector<int> v1;
v1.PushBack(1);
v1.PushBack(2);
v1.PushBack(3);
for (size_t i=0;i<v1.Size();i++)
{
cout << v1[i] << " ";
}
cout << endl;
Vector<double> v2;
v2.PushBack(1.1);
v2.PushBack(2.2);
v2.PushBack(3.3);
for (size_t i = 0; i < v2.Size(); i++)
{
cout << v2[i] << " ";
}
cout << endl;
}
四、模板参数
1.分类:模板参数分为类型形参和非类型形参。
2.类型模板参数:模板参数列表中,跟在class或typename后的参数。
3.非类型模板参数:参数列表中,可当作常量使用。不能为浮点数,类对象和字符串。
template<typename T,size_t N=10> //<类型模板参数,非类型模板参数>
class Array
{
public:
T& operator[](size_t index)
{
return _array[index];
}
const T& operator[](size_t index)const
{
return _array[index];
}
size_t Size()
{
return _size;
}
bool Empty()
{
return _size == 0;
}
private:
T _array[N];
size_t _size;
};