泛型编程
泛型编程:C++中一种使用模板来实现代码重用和类型安全的编程范式。它允许程序员编写与数据类型无关的代码,从而可以用相同的代码逻辑处理不同的数据类型。模板是泛型编程的基础
模板
模板分为两类:
- 函数模板
- 类模板
函数模板
函数模板:函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生
函数的特定类型版本。
//函数模板格式
template<class T>
void Sawp(T& left,T& right)
{
T tmp=left;
left=right;
right=tmp;
}
代码中的class
也可也换成typename
,但记住,class
不能用struct
代替。
原理: 编译器通过你编写的模板,再根据你传入的参数,自行生成对应的函数,调用的就是这个编译器自行生成的函数
假设你传入的两个参数都是int
,那么编译器就会创建一个形参是int
类型的模板
假设你传入的两个参数都是double
,那么编译器就会创建一个形参是double
类型的模板
举个例子:
//这里两处函数调用,看似调用的是一个函数,但实际上时调用了两个函数
//(函数调用要建立栈帧,一个是int类型,一个double类型,类型大小都不一样,更不可能调用的是同一个函数了),
//这个可以从汇编层来观察
template<typename T>
void Swap(T& left,T& right)
{
T temp = left;
left = right;
right = temp;
}
int main()
{
int x = 1, y = 2;
double m = 1.1, n = 2.2;
Swap(x,y);
Swap(m,n);
return 0;
}
但如果你传入的参数,一个是int
类型,一个是double
类型,那么模板参数就不能这么写。
template<class T1,class T2>
void Sawp( T1& left, T2& right)
{
T1 temp = left;
left = right;
right = temp;
}
像这样的,只有一个模板参数的,一次只能接收一个类型,当你把第一个int
类型的参数传进来后,第二个double
类型的参数它就穿不进来了,因为模板函数不允许自动类型转换。
函数模板实例化
用不同类型的参数使用函数模板时,称为函数模板的实例化:
- 隐式实例化
- 显示实例化
隐式实例化
template<typename T>
void Swap(const T& left,const T& right)
{
T temp = left;
left = right;
right = temp;
}
int main()
{
int x=1,y=2;
double m=1.1,n=2.2;
Sawp(x,y);//这便是隐式实例化,不显示的规定模板参数的实际类型
return 0;
}
显示实例化
template<typename T>
void Swap(const T& left,const T& right)//因为显示实例化存在类型转换,所以需要加const
{
T temp = left;
left = right;
right = temp;
}
int main()
{
int x=1,y=2;
double m=1.1,n=2.2;
Sawp<int>(x,m);//这是显示实例化,通过函数名后的<>来显示的规定模板参数的实际类型
Sawp(x,(int)m);//这不是显示实例化,但是你也可以通过强转来通过编译
return 0;
}
模板参数的匹配原则
一个非模板函数允许和一个同名的模板函数同时存在。
当非模板函数满足调用条件时,则会直接调用非模板函数,如果不满足条件,则会调用模板函数。
类模板
类模板的定义格式
template<class T1,class T2....class Tn>
class 类模板名
{
//....
};
举个例子:
template<class T>
class Stakc
{
public:
Stack(size_t capacity = 4)
{
_array = new T[capacity];
_capacity = capacity;
_size = 0;
}
private:
T* _array;
size_t _size;
size_t _capacity;
};
模板不建议声明和定义分开来写:
template<class T>
class Stakc
{
public:
Stack(size_t capacity = 4)
{
_array = new T[capacity];
_capacity = capacity;
_size = 0;
}
void Push(const T& data);
private:
T* _array;
size_t _size;
size_t _capacity;
};
template<class T>
void Stack<int>::Push(const T& data)
{
// 扩容
_array[_size] = data;
++_size;
}
类模板实例化
类模板实例化与函数模板实例化不同,类模板实例化需要在类模板名字后跟<>,然后将实例化的类型放在<>中即可,类模板名字不是真正的类,而实例化的结果才是真正的类
// Stack是类名,Stack<int>才是类型
Stack<int> st1; // int
Stack<double> st2; // double