文章目录
- 前言
- 1、反泛型编程
- 2、函数模板
- (1)、函数模板概念
- (2)、函数模板定义格式
- (3)、函数模板实例化
- (4)函数模板参数匹配原则
- 3、类模版
- (1)类模板实例化
- (2)类模板实现Stack(压/出栈函数)
前言
此篇主要描述函数模板的概念、格式以及实例化等;
1、反泛型编程
有学Java语言的同学,会听过里面的泛型。简单说就是给一个函数框架,可以实现调用不同类型的函数。是代码复用的手段。然而模版就是泛型编程的基础。
接下来看一下函数模板:
2、函数模板
此处先用一个例子引入:
改写后:
从上面可以看出模板的便利之处,可以减少代码量,提高效率,接下来看一看模板的概念和格式定义🚗🚗🚗🚗
(1)、函数模板概念
①概念:函数模板是一种允许程序员编写一个可以处理多种数据类型的函数的方法。它通过使用虚拟类型参数来代替具体的类型,使得函数可以处理不同类型的数据,从而实现了代码的复用和灵活性。
(2)、函数模板定义格式
template<typename T1, typename T2,…,typename Tn>这是模板的关键字。
注意:typename是用来定义模板参数关键字,也可以使用class(切记:不能使用struct代替
class)
template<class T>
//template<typename T>
void Swap(T& x, T& y)
{
T tmp = x;
x = y;
y = tmp;
}
(3)、函数模板实例化
用不同类型的参数使用函数模板时,称为函数模板的实例化。
模板参数实例化分为:隐式实例化和显式实例化。
- 隐式实例化:
template<class T>
T Add(const T& a,const T& b)
{
return a + b;
}
int main()
{
int a1 = 10, a2 = 20;
double b1 = 2.1, b2 = 3.0;
cout << Add(a1, a2) << "\n";
cout << Add(b1, b2) << "\n";
//出现两种类型的时候,时有两种处理方式:1. 用户自己来强制转化 2. 使用显式实例化
cout << Add(a1, (int)b1) << "\n";
return 0;
}
- 显示实例化:在调用函数名后的<>中指定模板参数的实际类型
//显示实例化
cout << Add<int>(a1, a2) << "\n";
(4)函数模板参数匹配原则
①非模板函数可以和一个同名的模板函数同时存在,并且模板函数可以被实例化为非模板函数。
②模板函数不允许自动类型转换,但普通函数可以进行自动类型转换。
③非模板函数和模板函数同名的时候,在其他参数以及返回值都相同的时候,会优先调用非模板函数,不会通过模板函数生成一个实例。但是模板函数中有更匹配的函数,那么会选择模板函数。
int Add(int a, int b)
{
return a + b;
}
template<class T>
T Add(const T& a,const T& b)
{
return a + b;
}
int main()
{
int a1 = 10, a2 = 20;
double b1 = 2.1, b2 = 3.0;
//cout << Add(a1, a2) << "\n";
//cout << Add(b1, b2) << "\n";
//cout << Add(a1, (int)b1) << "\n";
显示实例化
//cout << Add<int>(a1, a2) << "\n";
cout<<Add(1, 2)<<"\n"; // 与非函数模板类型完全匹配,不需要函数模板实例化
cout << Add(1, 2.0) << endl;//非模板函数,会自动类型转换
return 0;
}
3、类模版
函数模板是在函数前面加template<class T,……>,因此类模版格式类似的。
template<class T1, class T2, ..., class Tn>
class 类模板名
{
// 类内成员定义
};
(1)类模板实例化
类模板实例化与函数模板实例化不同,类模板实例化需要在类模板名字后跟<>,然后将实例化的类型放在<>中即可,类模板名字不是真正的类,而实例化的结果才是真正的类。
// Stack是类名,Stack<int>才是类型
Stack<int> st1; // int
Stack<double> st2; // double
(2)类模板实现Stack(压/出栈函数)
#define _CRT_SECURE_NO_WARNINGS 1
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
template<typename T>
class Stack
{
public:
Stack(size_t capacity = 4)
{
_array = new T[capacity];
_capacity = capacity;
_size = 0;
}
void Push(const T& data);
T GetTop();
void Pop();
~Stack()
{
delete[] _array;
_array = nullptr;
_size = _capacity = 0;
}
private:
T* _array;
size_t _capacity;
size_t _size;
};
template<typename T>
void Stack<T>::Push(const T& data)
{
if (_size == _capacity)
{
//开新空间
T* tmp = new T[_capacity * 2];
//拷贝新空间
memcpy(tmp, _array, sizeof(T) * _size);
//释放原空间
delete[] _array;
//指向新空间
_array = tmp;
_capacity *= 2;
}
_array[_size++] = data;
}
template<typename T>
T Stack<T>::GetTop()
{
if (_size == 0)
{
return -1;
}
return _array[_size-1];
}
template<typename T>
void Stack<T>::Pop()
{
if (_size == 0)
{
return;
}
_size--;
}
int main()
{
Stack<int> st1;
st1.Push(1);
st1.Push(2);
st1.Push(3);
st1.Push(4);
st1.Push(5);
cout << st1.GetTop() << "\n";
st1.Pop();
cout << st1.GetTop() << "\n";
return 0;
}