文章目录
- 前言
- 函数模版
- 函数模版的原理
- 函数模版的实例化
- 类模版
- 类模版的实例化
前言
当我们使用一个通用的函数:
//为每一个类型都编写一个重载版本
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;
}
这种方法的缺点是显而易见的:随着需要交换的类型的增加,你需要不断地编写新的重载函数。这不仅繁琐,而且不灵活,因为它不能自动适应未来可能出现的新类型。
函数模板提供了一种更加灵活和通用的解决方案。你可以定义一个模板函数,该函数可以接受任意类型的参数,并在编译时根据传入的参数类型生成相应的函数版本。
函数模版
函数模版的格式:
template<typename T1, typename T2,…,typename Tn>
返回值类型 函数名(参数列表){}
//函数模版
template<class T>
void Swap(T& m, T& n)
{
T tmp = m;
m = n;
n = tmp;
}
注意:typename是用来定义模板参数关键字,也可以使用class(切记:不能使用struct代替class)
template<typename T>
void Swap(T& m, T& n)
{
T temp = m;
m = n;
n = temp;
}
template<class T>
void Swap(T& m, T& n)
{
T tmp = m;
m = n;
n = tmp;
}
int main()
{
int i = 1, j = 2;
double x = 1.1, y = 2.2;
Swap(i, j);
Swap(x, y);
//Swap(i, x); 函数模版不能传不同类型的参数
return 0;
}
函数模版的原理
函数模版本身并不是函数,模版只是将我们做的事重复的事交给了编译器
函数模版的实例化
用不同类型的参数使用函数模板时,称为函数模板的实例化。模板参数实例化分为:隐式实例化和显式实例化。
这里就是要解决这个问题
有两种处理方式
- 强制类型转换
- 使用显式实例化
template<class T>
void Swap(const T& m, const T& n)
{
T tmp = m;
m = n;
n = tmp;
}
int main()
{
int i = 1, j = 2;
double x = 1.1, y = 2.2;
//推导实例化(自己动手强转)
Swap(i, (int)x);
Swap((double)i, x);
//显示实例化
Swap<int>(i, x);
return 0;
}
如果我就要用 Swap(i,x) 来实现呢?
template<class T1,class T2>
T1 Swap(const T1& m, const T2& n)
{
T1 tmp = m;
m = n;
n = tmp;
}
有种场景我们必须用显示实例化:
template<class T>
T* func1(int n)
{
return new T[n];
}
int main()
{
//func1(10); 编译器无法推导出类型
int* p = func1<int>(10);
return 0;
}
如果函数和模板同时存在,会先调用函数
template<class T>
T ADD(const T& left, const T& right)
{
return left + right;
}
int ADD(const int& x, const int& y)
{
return (x + y) * 10;
}
int main()
{
int a = 5;
int b = 10;
cout<<ADD(a, b)<<endl;
return 0;
}
类模版
类模版的格式:
template<class T1, class T2, ..., class Tn>
class 类模板名
{
// 类内成员定义
};
类模版实现栈
template<class T>
class Stack
{
public:
Stack(int n = 4)
:_arr(new T[n])
,_size(0)
,_capacity(n)
{}
~Stack()
{
delete[] _arr;
_arr = nullptr;
_size = _capacity = 0;
}
void Push(const T& x)
{
if (_size == _capacity)
{
T* tmp = new T[_capacity * 2];
memcpy(tmp, _arr, sizeof(T) * _size);
delete[] _arr;
_arr = tmp;
_capacity *= 2;
}
_arr[_size++] = x;
}
//...
private:
T* _arr;
int _size;
int _capacity;
};
将栈的所有数据和方法封装在类内部,所以只有类成员函数才可以访问(最好不要类里声明,类外定义,除非在类外使用template<>语法来指明你正在定义的是哪个模板参数的成员函数),而且,通过类模版,不同的类型都可以实现栈,安全性也得到了提升。
template<class T>
void Stack<T>::Push(const T& x)
{
if (_size == _capacity)
{
T* tmp = new T[_capacity * 2];
memcpy(tmp, _arr, sizeof(T) * _size);
delete[] _arr;
_arr = tmp;
_capacity *= 2;
}
_arr[_size++] = x;
}
类模版的实例化
类模版只能使用显示实例化
int main()
{
Stack<int>str1;
str1.Push(1);
str1.Push(2);
str1.Push(3);
Stack<double>str2;
str2.Push(1.1);
str2.Push(2.2);
str2.Push(3.3);
return 0;
}
希望这篇博客对你有所帮助!!!