1.函数模板
为什么有模板C++要引入模板??
如果我们要实现一个交换函数,比如
#include<iostream>
#include<string>
using namespace std;
void swap(int& A, int& B)
{
int temp = A;
A = B;
B = temp;
}
int main()
{
int a = 10;
int b = 20;
swap(a, b);
cout << a << " " << b << endl;
return 0;
}
那么当我要同时进行 double类型 ,float类型,int类型等各种类型之间的转换
和不同类型之间的转换,那么我们是不是要写很多代码 ??
比如
#include<string>
using namespace std;
void swap(float& A, float& B)
{
int temp = A;
A = B;
B = temp;
}
void swap(double& A, double& B)
{
int temp = A;
A = B;
B = temp;
}
void swap(int& A, int& B)
{
int temp = A;
A = B;
B = temp;
}
int main()
{
double c = 60.4;
double d = 50.3;
float e = 40.2;
float f = 30.1;
int a = 10;
int b = 20;
swap(a, b);
swap(c, d);
swap(e, f);
cout << e << " " << f << endl;
cout << c << " " << d << endl;
cout << a << " " << b << endl;
return 0;
}
那么有没有什么办法,让我写一个函数就够用呢???
C++为我们提供了一个模板
我们只要写一个函数,那么这个函数的形参类型会随着我们给的实参类型而变化
我们给什么实参类型,这个形参就变成什么。
那么这样是不是就方便了很多
模板的格式
template<class T1, class T2,......,class Tn>
返回值类型 函数名(参数列表){}
上述class可以用typename代替
#include<iostream>
#include<string>
using namespace std;
template<class T>
void Swap(T& A, T& B)
{
T temp = A;
A = B;
B = temp;
}
int main()
{
double c = 60.4;
double d = 50.3;
float e = 40.2;
float f = 30.1;
int a = 10;
int b = 20;
Swap(a, b);
swap(c, d);
swap(e, f);
cout << e << " " << f << endl;
cout << c << " " << d << endl;
cout << a << " " << b << endl;
return 0;
}
根据结果我们可以判断出,我们只构造了一个函数,但可以进行多个类型的初始化
编译器通过模板,在程序进行时根据情况通过这个模板来构建几个不同的函数
那我们可不可以将两个不同类型的数据进行交换呢
我们可以看到,当我们将int类型数据和float类型数据进行交换时编译器会报错。
void Swap(T& A, T& B)
{
T temp = A;
A = B;
B = temp;
}
如上图,这是因为当我们传第一个实参时,T就识别到了实参的类型,那么T就会转化为这个实参的类型,之后在这个函数中这个T就会一直是这个类型,所以传第二个参数时会报错。
那么我们要怎么解决这个问题呢??
我们可以使用两个模板类型来解决这个问题
#include<iostream>
#include<string>
using namespace std;
template<class T,class P>
void Swap(T& A, P& B)
{
T temp = A;
A = B;
B = temp;
}
int main()
{
double c = 60.4;
double d = 50.3;
float e = 40.2;
float f = 30.1;
int a = 10;
int b = 20;
Swap(a, f);
cout << a << " " << f << endl;
return 0;
}
运行结果
我们可以看到,当我交换a和f的数据时,发生了类型转换,30.1变为了30。
我们除此之外我们还可以用别的方法来进行交换,比如
强制转换类型
#include<iostream>
#include<string>
using namespace std;
template<class Y>
Y Add(const Y& a, const Y& b)
{
return a + b;
}
int main()
{
float f = 30.1;
int a = 10;
cout << Add(a, (int)f) << endl;
cout << a << " " << f << endl;
return 0;
}
其中f的类型转化为了int。
但是我们需要注意,这个f在被转化为int时,是一个临时变量,它将它这个值转递过去时,是一个临时变量,我们需要用const来接收这个临时变量。
显示实例化也可以解决上面的问题
我们用这个模板来实例化一个函数’
比如
#include<iostream>
#include<string>
using namespace std;
template<class Y>
Y Add(const Y& a, const Y& b)
{
return a + b;
}
int main()
{
float f = 30.1;
int a = 10;
cout << Add<int>(a, f) << endl;
cout << a << " " << f << endl;
return 0;
}
显示实例化就是在函数名和()中间加一个<类型名>来将里面的参数强制转化为想要的类型
模板函数匹配原则
一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板可以被实例化为这个非模板函数
#include<iostream>
#include<string>
using namespace std;
template<class Y>
Y Add(const Y& a, const Y& b)
{
return a + b;
}
int Add(const int& a, const int & b)
{
return a + b;
}
int main()
{
float f = 30.1;
int a = 10;
cout << Add<int>(a, f) << endl;
cout << a << " " << f << endl;
return 0;
}
对于非函数模板和同名函数模板,如果其它条件相同,在调动时会优先调用非函数模板而不会从该模板产生出一个实例。如果模板可以产生一个具有更好匹配的函数,那么将选择模板。
2.类模板
template<class T1, class T2, ..., class Tn>
class 类模板名 { // 类内成员定义};
#include<iostream>
#include<string>
using namespace std;
template<class T>
class Stack
{
public:
Stack(int n = 4)
{
arr = new T[4];
size = 0;
capacity = n;
}
void pop()
{
size--;
}
void push(T date)
{
if (size == capacity)
{
T*temp = new T[capacity * 2];
memcpy(temp, arr, capacity * 2);
delete arr;
arr = temp;
capacity = capacity * 2;
}
arr[size] = date;
size++;
}
void print()
{
for (int i = 0; i < size; i++)
{
cout << arr[i] << endl;
}
}
private:
T* arr;
int size;
int capacity;
};
int main()
{
Stack<int> ST(10);
ST.push(10);
ST.push(20);
ST.push(30);
ST.push(40);
ST.push(50);
ST.pop();
ST.pop();
ST.pop();
ST.print();
}
类模板实例化
类模板实例化与函数模板实例化不同,类模板实例化需要在类模板名字后跟<>,然后将实例化的类型放在<>中即可,类模板名字不是真正的类,而实例化的结果才是真正的类
/ / Stack是类名,Stack<int>才是类型
Stack<int> st1; // intStack<double> st2; // double