模板的引入
C++是泛型编程(更广泛)
在C++中要完成函数交换可以用以下代码:
void Swap(int& x1, int& x2)
{
int x = x1;
x1 = x2;
x2 = x;
}
void Swap(double& x1, double& x2)
{
double x = x1;
x1 = x2;
x2 = x;
}
void Swap(char& x1, char& x2)
{
char x = x1;
x1 = x2;
x2 = x;
}
函数模板
但是这样子就很麻烦,因此引入了函数模板
模板参数列表 – 参数类型
template <class T> // template表示模板
// 也可以写template <typename T>
// 这里不一定要用T,T叫模板参数列表,T代表type
// 若要多个T则:template <class T1, class T2>,定义多个类型
void Swap(T& x1, T& x2) // 函数参数列表
{
T x = x1;
x1 = x2;
x2 = x;
}
函数模板的实例化
下面三个调用调用的是同一个函数吗?——不是,给变量开空间类型不一样
template <class T>
void Swap(T& x1, T& x2)
{
T x = x1;
x1 = x2;
x2 = x;
}
int main()
{
int a = 0, b = 1;
double c = 1.1, d = 2.22;
char e = 'A', f = 'B';
Swap(a, b);
Swap(c, d);
Swap(e, f);
return 0;
}
实际上调用的是模板实例化出来的函数
template<class T>
T Add(const T& left, const T& right)
{
return left + right;
}
int main()
{
int a1 = 10, a2 = 20;
double d1 = 10.1, d2 = 20.2;
// 里面必须是同一类型,因为同一个T不可能为int和double两种类型
cout << Add(a1, a2) << endl;
cout << Add(d1, d2) << endl;
// 解决方式1——强制转换,这样子就传的是相同类型了
cout << Add((double)a1, d2) << endl;
// 解决方式2——显示实例化
// 指明了是什么类型,在函数名和参数列表之间加<>
// 为了计算两个类型不同的变量
// 因为他们两个是用同一个T接受的
cout << Add<int>(a1, d2) << endl;
cout << Add<double>(a1, d2) << endl;
return 0;
}
template <class T>
T Add(const T& left, const T& right)
{
return left + right;
}
int main()
{
int a1 = 10, a2 = 20;
double d1 = 10.1, d2 = 20.2;
cout << Add(a1, a2) << endl;
cout << Add(d1, d2) << endl;
// 显示实例化
cout << Add<int>(a1, d2) << endl;
cout << Add<double>(d1, a2) << endl;
return 0;
}
若有两个Add函数,则应该调用下面的Add函数
会优先调用普通函数,如果没有再去调用函数模板
类模板
// 类模板到时候会实例化出具体的类
template <class T>
class Stack
{
public:
Stack(int capacity = 4)
:_top(0)
, _capacity(capacity)
{
_a = new T[_capacity]; // new失败是抛异常
}
~Stack()
{
delete[] _a;
_a = nullptr;
_capacity = _top = 0;
}
private:
T* _a;
int _top;
int _capacity;
};
int main()
{
// 为了让同一个栈使用两个类型,就不能使用之前typedef了
// Stack st1; // 存int
// Stack st2; // 存double
// 上面两种没办法自己去推类型,所以必须要显示实例化
// 在类后面加类型
Stack<int> st1; // 存int,Stack<int>是类型
Stack<double> st2; // 存double
return 0;
}
在类里面声明,外面定义时的特殊情况:
template <class T>
class Stack // Stack是类名 Stack<T>是类型
{
public:
Stack(int capacity = 4)
:_top(0)
, _capacity(capacity)
{
_a = new T[_capacity]; // new失败是抛异常
}
~Stack()
{
delete[] _a;
_a = nullptr;
_capacity = _top = 0;
}
void Push(const T& x);
private:
T* _a;
int _top;
int _capacity;
};
// 写在外面时,不知道这里的T是从哪里来的
void Push(const T& x)
{
// ...
}
正确方法是:
template <class T>
void Stack<T>::Push(const T& x) // 类模板完整类型是Stack<T>
{
// ...
}