1.问题引入
#include<iostream>
using namespace std;
void Swap(int& a, int& b)
{
int tmp = a;
a = b;
b = tmp;
}
void Swap(char& a, char& b)
{
char tmp = a;
a = b;
b = tmp;
}
void Swap(double& a, double& b)
{
double tmp = a;
a = b;
b = tmp;
}
我们查看上述代码发现,这几个函数都是完成值的交换,代码的复用率低。泛型编程:使用模版实现与类型无关的代码。
我们能不能告诉编译器一个模子,让编译器根据不同类型生成对应代码函数呢?
2.模版
2.1函数模版
1.概念:
函数模版代表了一类函数,该函数模版与类型无关,在被调用时根据参数类型实例化出特定的函数代码。
2.用法:
tmplate<typename T>/tmplate<class T>
函数返回值 函数名(参数列表){}
template<typename T>//也可以用template<class T>
void Swap(T& x, T& y)
{
T tmp = x;
x = y;
y = tmp;
}
int main()
{
int x = 10;
int y = 20;
Swap(x, y);//当我们要指定类型时Swap<类型>Swap(x,y)
cout << x<<" "<< y;
return 0;
}
3.原理:
我们写了模版,在预处理阶段,模版会根据传入的参数类型推演实例化出对应类型的函数,实际上实例化出的还是用我们开头写的那些代码。
注意:模版并不是函数,而是蓝图,是编译器产生特定具体类型函数的模具,因此编译器并不会检查出模版的错误,当模版实例化出函数时,检查的是函数代码的错误,当我们没有实例化模版时,编译器也就检查不出一些错误
例如下述代码,即使我们tmp写错成tm,编译也能通过
template<class T>
void Swap(T& x, T& y)
{
T tmp = x;
x = y;
y = tm;
}
int main()
{
int x = 10;
int y = 20;
//Swap<int>(x, y);
//cout << x<<" "<< y;
return 0;
}
4.函数模版的实例化
分为显示实例化和隐示实例化,具体区别如下:
template<typename T>
T Add(const T& x, const T& Y)
{
return x + y;
}
int main()
{
Add(3, 4);//隐式实例化-----编译器通过实参推演出T类型
Add<int>(3, 4);//显示实例化-----手动给出T的类型
//当下面情况要使用显示实例化,或者强转,不然编译器会报错
Add(3, (int)4.0);
Add<int>(3, 4.5);
return 0;
}
5.模版参数的匹配原则
①一个非模版函数与一个同名的模版函数同时出现,而且该函数模版可以实例化这个非模版函数,此时,如果类型和非模版函数匹配会优先调用非模版函数,因为可以减少实例化
int Add(int x, int y)
{
return x + y;
}
template<typename T>
T Add(const T& x, const T& Y)
{
return x + y;
}
int main()
{
Add(1, 2);//会调用第一个add
Add(1.0, 1.0);//会调用第二个add
return 0;
}
②在①的基础上,如果模版函数可以生成更好的函数,那么会调用模版函数实例化出对应的函数.
int Add(int x, int y)
{
return x + y;
}
template<typename T1 ,typename T2>
T1 Add(const T1& x, const T2& y)
{
return x + y;
}
int main()
{
Add(1.0, 1);//会调用第二个add
return 0;
}
2.2类模版
引入:我们如何在一个进程中同时创建两个栈,一个栈存储int类型数据,一个栈存储double类型数据,在C语言中实现很麻烦,而C++中引入了类模版,就很简单。
1.类模版的定义格式
template<typename/class T>
class 类模版名{类内成员};
注意:模版中函数放在类外定义时,需要加模版参数列表。与函数实例化不同,类模版实例化需要在类模版名后加<类型>,类模版名是类名,不是类型,用类模版名<类型> 实例化出的真正的类型。而普通的类。既是类名也是类型。
例:
template<class T>
class Stack
{
public:
void print();
private:
T* _str;
int _capacity;
int _size;
};
template<class T>
void Stack<T>::print()
{
cout << "a";
}
int main()
{
Stack<int> Stack_int;//实例化出的Stack<int>才是真正的类型,Stack_int是用类创建的一个对象
Stack_int.print();
return 0;
}