模板初始(利用重载进行内容调换)
什么是模板?
为什么需要使用模板?
用他的目的是什么?
先举一个例子
如果需要调换两个数的位置,代码该怎么写?
最简单的方法肯定是这样的:
#include <iostream>
using namespace std;
void Swap(int &a, int &b)
{
int tmp = a;
a = b;
b = tmp;
}
void main()
{
int a = 1;
int b = 2;
Swap(a, b);
cout << "a = " << a << ", b = " << b << endl;
system("pause");
}
写个函数一调换就行了
那要是现在要求换两个字符呢?
也简单,c++中可以进行函数重载,加一个就行了
#include <iostream>
using namespace std;
void Swap(char &a, char &b)
{
char tmp = a;
a = b;
b = tmp;
}
void Swap(int &a, int &b)
{
int tmp = a;
a = b;
b = tmp;
}
void main()
{
int a = 1;
int b = 2;
Swap(a, b);
cout << "a = " << a << ", b = " << b << endl;
char c = 'C';
char d = 'D';
Swap(c, d);
cout << "c = " << c << ", d = " << d << endl;
system("pause");
}
那么要是要求double?
没事,加!
不过这样一来感觉好像有点low,缺点也很明显:
1、重载的函数仅仅是类型不同,代码的复用率比较低,而且每有一个新的函数类型就要增加相应的函数
2、代码的维护性比较低,一个出错可能其他的也会出错
那有没有一种方法,可以一步到位?
这就要使用到模板了
模板的目的与要求
模板的目的就是通用
模板的要求是将类型进行参数化
用模板解决调换问题
template<typename Type>
void Swap(Type &a, Type &b)
{
Type tmp = a;
a = b;
b = tmp;
}
看起来差别好像也不大,测试一下
void main()
{
char a = 'A';
char b = 'B';
Swap(a, b);
cout << "a = " << a << ", b = " << b << endl;
int c = 1;
int d = 2;
Swap(c, d);
cout << "c = " << c << ", d = " << d << endl;
double e = 11.11;
double f = 22.22;
Swap(e, f);
cout << "e = " << e << ", f = " << f << endl;
system("pause");
}
这下是三种类型全部包进去了,再看看结果
完工,很显然这个函数做到了通用,可以称之为模板
那这是怎么做到的?
改动一下函数,让他显示每次调换时的类型
#include <iostream>
using namespace std;
template<typename Type>
void Swap(Type &a, Type &b)
{
cout << "Type=" << typeid(Type).name() << endl;
Type tmp = a;
a = b;
b = tmp;
}
void main()
{
char a = 'A';
char b = 'B';
Swap(a, b);
cout << "a = " << a << ", b = " << b << endl;
int c = 1;
int d = 2;
Swap(c, d);
cout << "c = " << c << ", d = " << d << endl;
double e = 11.11;
double f = 22.22;
Swap(e, f);
cout << "e = " << e << ", f = " << f << endl;
system("pause");
}
结果显示,当我们是char类型时,所调用的类型就是char,int时便为int ···
即根据类型的不同推出的结果也不同
函数模板
概念
函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生的函数的特定类型版本
格式
template<typename T1 , typename T2 , ... , typename Tn>
返回值类型 函数名(参数列表){}
模板不支持隐式转换
先看下边的代码
#include <iostream>
using namespace std;
int Add(int a, int b)
{
return a + b;
}
void main()
{
int ret = Add(1, 2);
system("pause");
}
这是一个求两个int值相加的代码
现在将其更改
#include <iostream>
using namespace std;
int Add(int a, int b)
{
return a + b;
}
void main()
{
int ret = Add(1, 2);
ret = Add(1.2, 2.3);
system("pause");
}
发现这样也是能够跑成功的,即在其中发生了隐式转换,将double类型强制转成了int类型,从而能够调用前边的函数
此时再添加一组函数
#include <iostream>
using namespace std;
int Add(int a, int b)
{
return a + b;
}
double Add(double a, double b)
{
return a + b;
}
void main()
{
int ret = Add(1, 2);
ret = Add(1.2, 2.3);
system("pause");
}
此时就构成了函数的重载,int类型就调用int类型,double就调用double类型
那如果这么改呢?
#include <iostream>
using namespace std;
double Add(int a, double b)
{
return a + b;
}
void main()
{
int ret = Add(1, 2);
ret = Add(1.2, 2.3);
system("pause");
}
很显然也是能跑成功的
那么要是使用模板呢?
#include <iostream>
using namespace std;
template<typename Type>
Type Add(Type a, Type b)
{
cout << "Type=" << typeid(Type).name() << endl;
return a + b;
}
void main()
{
int ret = Add(1, 2);
ret = Add(1.2, 2.3);
system("pause");
}
可以看到这也是可行的,第一次调用时为int类型,第二次调用为double类型
那再改改呢?
#include <iostream>
using namespace std;
template<typename Type>
Type Add(Type a, Type b)
{
cout << "Type=" << typeid(Type).name() << endl;
return a + b;
}
void main()
{
int ret = Add(1, 2.1);
system("pause");
}
此时发现报错了,这就要提到模板一个最大的特点了:
模板不支持隐式转换
原因其实很简单,当使用第一个数和Type结合时,推导出来的类型是int类型,但当第二个数与Type结合时推导出来的却是double类型,此时无法确定类型,即产生了类型的二义性
那么如何解决?
方法一: 添加类型
#include <iostream>
using namespace std;
template<typename Type1, typename Type2>
Type1 Add(Type1 a, Type2 b)
{
return a + b;
}
void main()
{
int ret = Add(1, 2.1);
system("pause");
}
即让第一个数与Type1结合推导出类型int,第二个数与Type2结合推导出类型double,即可解决这个问题
方法二: 强制转换
void main()
{
int ret = Add((double)1, 2.1);
system("pause");
}
void main()
{
int ret = Add(1, (int)2.1);
system("pause");
}
只要能让他们的类型相同就行
方法三: 自暴自弃(划掉) 显式实例化
void main()
{
int ret = Add<int>(1, 2.1);
system("pause");
}
这样在传递的时候直接告诉函数我就是int类型的,也能解决冲突,同样尖括号中的内容也可以换成其他类型
模板函数
模板函数即通过函数模板与传递值类型结合出来的函数
举个例子
template<typename Type>
Type Add(Type a, Type b)
{}
这个就是函数模板↑
传递了
ret = Add (1, 2);
后的函数模板即
int Add(int a, int b)
{}
这个就是模板函数↑
类模板
定义格式
template(class T1, class T2, ... ,class Tn)
class 类模板名
{
//类内成员定义
};