一,泛型编程
编写与类型无关的通用代码,是代码复用的一种手段,模板是泛型编程的基础。
二,函数重载和函数模板的关联
函数重载:定义函数名相同而形参列表(形参个数或形参类别)不同的多个函数。。
函数模板:创建一类实现逻辑(函数体)一样,只是用到参数的类型不同的函数的公式。
区别:
1,函数重载用于定义功能相似的同名函数,提高函数的易用性,但代码复用率低,只要有新类型出现就要增加对应的函数,而且代码可维护性低;函数模板则用于为实现逻辑一样只是参数类型不同的一类函数提供统一的模板,提高了函数编写的效率。
2,形参列表:函数重载要求参数个数或类型不同,而函数模板则要求参数个数必须一样。
联系:函数模板也能进行函数重载
三,函数模板
概念:该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型版本。
格式:
template<typename T1,typename T2,…typename Tn>
返回值类型 函数名( 参数列表{}
(template可用class代替)
模板只是一个蓝图(设计的稿纸),它本身并不是函数,是编译器用使用方式产生特定具体类型函数的模具。
四,函数模板的实例化
1,隐式实例化:让编译器根据实参推演模板参数的实际类型(编译阶段)
2,显式实例化:在函数名后面<>中指定模板参数的实际类型
/函数模板的转化
template <class T>
T Add(const T& left, const T& right)
{
return left + right;
}
int main()
{
int a1 = 10, a2 = 20;
double d1 = 10.0, d2 = 20.0;
Add(a1, a2);
Add(d1, d2);
Add(a1, (int)d2);
// 对函数模板进行隐式实例化
// 同名函数与函数模板同时存在时,优先使用模板生成的同名函数
Add<>(1, 2);
Add<int>(a1, d2);
system("pause");
return 0;
}
由于在模板中,编译器不会进行类型转换操作,因此有两种处理方式:1,用户自己强制转化 2,使用显式实例化。
如果类型不匹配,编译器会尝试进行隐式转换,如果无法转换成功编译器将会报错。
五,函数模板匹配原则
1,一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这个非模板函数。
2,对于非模板函数和同名函数模板,如果其他条件都相同,在调用时会优先调用非模板函数而不会从该模板中产生出一个实例,如果模板可以产生一个具有更好匹配的函数,那么将选择模板。
3,函数模板不允许自动类型转换,但普通函数可以进行自动类型转换。
六,类模板
格式:template <class T1, class T2…class Tn>
class 类模板名
{
}
实例化:类模板的实例化需要在类模板名字后面跟<>,然后将实例化的类型放在<>中即可,类模板名字不是真正的类,而实例化的结果才是真正的类。
//用类模板写一个动态类型顺序表
#include<assert.h>
template<class T>
class SeqList
{
public:
SeqList(size_t capacity = 10)
:_array(new T[capacity])
, _size(0)
, _capacity(capacity)
{}
~SeqList()
{
delete[] _array;
_array = nullptr;
_capacity = 0;
_size = 0;
}
void PopBack()
{
--_size;
}
size_t size() const
{
return _size;
}
size_t capacity() const
{
return _capacity;
}
bool Empty() const
{
return 0 == _size;
}
T& operator[](size_t index)
{
assert(index < _size);
return _array[index];
}
const T& operator[](size_t index)const
{
assert(index < _size);
return _array[index];
}
void PushBack(const T& data);
private:
void _CheckCapacity()
{
if (_size == _capacity)
{
// 开辟新空间
T* array = new T[2 * _capacity];
// 拷贝元素
// memcpy(array, _array, _size*sizeof(T));
for (size_t i = 0; i < _size; ++i)
{
array[i] = _array[i];
}
// 释放旧空间
delete[] _array;
_array = array;
_capacity *= 2;
}
}
private:
T* _array;
size_t _size;
size_t _capacity;
};
template<class T>
void SeqList<T>::PushBack(const T&data)
{
_CheckCapacity();
_array[_size++] = data;
}
void TestSeqList()
{
SeqList<int> s1;
s1.PushBack(1);
s1.PushBack(2);
s1.PushBack(3);
s1.PushBack(4);
cout << s1.size() << endl;
cout << s1.capacity() << endl;
cout << s1[2] << endl;
s1[2] = 10;
SeqList<double> s2;
s2.PushBack(1.0);
s2.PushBack(2.0);
s2.PushBack(3.0);
s2.PushBack(4.0);
s2.PushBack(5.0);
cout << s2.size() << endl;
cout << s2.capacity() << endl;
}
int main()
{
TestSeqList();
system("pause");
return 0;
}