目录
一.泛型编程
二.模板
函数模板
类模板
一.泛型编程
在C++中,支持函数重载,如果我们通过函数重载实现通用的交换函数,写法如下:
void Swap(int& left, int& right)
{
int temp = left;
left = right;
right = temp;
}
void Swap(double& left, double& right)
{
double temp = left;
left = right;
right = temp;
}
void Swap(char& left, char& right)
{
char temp = left;
left = right;
right = temp;
}
......
非常冗余,于是我们引入泛型编程的概念:通过编写与类型无关的代码,实现代码的复用。而在C++中,模板就是泛型编程的基础。
二.模板
模板有两种:函数模板和类模板
函数模板
语法:
template<typename T1, typename T2, ..., typename T3>
返回值类型 函数名(参数列表){}
typename是用来定义函数模板的关键字,也可以使用class关键字。
样例:
//交换函数模板
template<typename T>
void Swap(const T& x, const T& y)
{
T tmp = x;
x = y;
y = tmp;
}
int main()
{
int i1 = 1, i2 = 2;
double d1 = 1.1, d2 = 2.2;
char c1 = 'a', c2 = 'b';
//隐式实例化
Swap(i1, i2);//隐式(推导)生成void Swap(const int& x, const int& y);
Swap(d1, d2);//隐式(推导)生成void Swap(const double& x, const double& y);
Swap(c1, c2);//隐式(推导)生成void Swap(const char& x, const char& y);
//显式实例化
float f1 = 1.1, f2 = 2.2;
Swap<float>(f1, f2);//显式(手动)生成void Swap(const float& x, const float& y);
return 0;
}
模板函数是一个蓝图,非具体函数,而是编译过程中,编译器根据蓝图生成了具体类型的函数。
模板参数实例化的两种方式:
隐式实例化:编译器根据实参推演模板参数的实际类型
显式实例化:函数名<>,在<>中指定模板参数的实际类型
如果一个非模板函数和同名函数模板同时存在,且调用时实参和非模板函数完全匹配,编译器会优先调用这个非模板函数。
类模板
语法:
template<typename T1, typename T2, ... , typename Tn>
class 类模板名
{
//成员定义
};
实现一个栈的类模板:
//Stack
template<typename T>
class Stack
{
public:
//构造函数
Stack(int n = 4)
:_arr(new T[n])
,_top(0)
,_capacity(n)
{}
//析构函数
~Stack()
{
delete[] _arr;
_arr = nullptr;
_top = _capacity = 0;
}
void Push(const T& x)
{
T* tmp = new T[_capacity * 2];
memcpy(tmp, _arr, sizeof(T) * _top);
delete[] _arr;
_arr = tmp;
_capacity *= 2;
_arr[_top++] = x;
}
void Pop()
{
_top--;
}
//...
private:
T* _arr;
int _top;
int _capacity;
};
int main()
{
//Stack<int>和Stack<double>是类型,Stack仅仅是类名
Stack<int> st_i;//存储int类型数据的栈
Stack<double> st_d;//存储double类型数据的栈
return 0;
}
上述代码中,Stack<int>和Stack<double>是显式实例化出的两个存储不同数据类型的栈,它们属于不同的类型。
类模板实例化需要在类模板名字后跟<>,然后将实例化的类型放在<>中即可,类模板名字不是真正的类,而实例化的结果才是真正的类。
今天的内容就到这,感谢大家的支持!