泛型编程:编写与类型无关的通用代码,是代码复用的一种手段模板是泛型编程的基础
模板又分为函数模板和类模板
函数模板:
该函数与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型版本
template是用来定义模板参数的关键字,也可以使用class(不能使用struct)
template<class T>
T add(T&left, T&right)
{
return left + right;
}
int main()
{
int x1 = 10;
int x2 = 20;
double s1 = 30.1;
double s2 = 40.2;
add(x1, x2);
add(s1, s2);
return 0;
}
在编译阶段,编译器根据传入的实参类型来推演生成对应类型的函数以供调用
例如:当用double类型使用函数模板时,编译器通过对实参类型的推演将T确定为double类型
然后产生一份专门处理double类型的代码。
显式实例化:在函数名后的<>中指定模板参数的实际类型
int main()
{
int a=10;
double b=20.0;
显式实例化
add<int>(a,b);
return 0;
}
模板参数的匹配原则:
一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这个非模板函数
参数如果和非模板函数匹配,就调用非模板函数
add<int>(1,2) 这种的调用编译器特化的add版本 加了<>的调用模板生成的函数
类模板的实例化
类模板实例化需要再类模板名字后跟<>,然后将实例化的类型放在<>中,类模板名字不是真正的类
实例化的结果才是真正的类
//Vector类名,Vector<int>才是类型
Vector<int>s1;
Vector<double>s2;
C++实现动态顺序表
template<class T>
class Vector
{
public:
Vector();
~Vector()
{
if (_a)
{
delete[] _a;
_size = _capacity = 0;
}
}
void PushBack(const T&x)
{
if (_size == _capacity)
{
size_t newcapacity = _capacity == 0 ? 10 : _capacity * 2;
T* tmp = new T[newcapacity];
if (_a)
{
memcpy(tmp, _a, sizeof(T)*_size);
delete[] _a;
}
_a = tmp;
_capacity = newcapacity;
}
_a[_size] = x;
_size++;
}
T&operator[](size_t pos)
{
return _a[pos];
}
size_t Size()
{
return _size;
}
private:
T* _a;
size_t _size;
size_t _capacity;
};
template<class T>
Vector<T>::Vector()//类成员的初始化
:_a(nullptr)
, _capacity(0)
, _size(0)
{}
int main()
{
Vector<int>s1;
s1.PushBack(1);
s1.PushBack(2);
s1.PushBack(3);
s1.PushBack(4);
for (size_t i = 0; i < s1.Size(); ++i)
{
cout << s1[i] << " " << endl;
}
Vector<double>s2;
s2.PushBack(1.11);
s2.PushBack(2.11);
s2.PushBack(3.11);
s2.PushBack(4.11);
for (size_t i = 0; i < s2.Size(); ++i)
{
cout << s2[i] << " " << endl;
}
return 0;
}