引入
在C语言中完成两数交换,如果每次交换的类型不同,我们需要写多个函数就和下面一样。C语言中得保证函数名字的不同来保证函数之间不会冲突。在C++中就有函数重载和模板了。
cpp
#include <stdio.h>
void Swap1(int* a, int* b)
{
int tmp = *a;
*a = *b;
*b = tmp;
}
void Swap2(float* a, float* b)
{
float tmp = *a;
*a = *b;
*b = tmp;
}
int main()
{
float a1 = 2.2, a2 = 1.1;
Swap2(&a1, &a2);
return 0;
}
C++中的函数重载
C++中摒弃了C语言中函数名不可以相同的特性,因为就像swap函数,他是交换函数,让这一个函数名完成多种类型变量的交换多舒服,所以C++中让参数的不同来判断不同的函数,相同的函数名和不同的参数就构成了函数重载(函数的返回值不可以作为不同函数的区分点)
这样写很多个相同的函数也是很麻烦的,这时候C++就引出了模板,直接简化了。
cpp
#include <iostream>
using namespace std;
void Swap(int& a, int& b)
{
int tmp = a;
a = b;
b = tmp;
}
void Swap(float& a, float& b)
{
float tmp = a;
a = b;
b = tmp;
}
void Swap(double& a, double& b)
{
double tmp = a;
a = b;
b = tmp;
}
int main()
{
double a = 1.1, b = 2.2;
Swap(a, b);
int a1 = 1, b1 = 2;
Swap(a1, b1);
float a2 = 3.3, b2 = 4.4;
Swap(a2, b2);
return 0;
}
函数模板
函数模板的概念:函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参的类型产生特定的类型。
1.typename是用来定义模板参数关键字,也可以使用class(不可以使用struct)
cpp
#include <iostream>
using namespace std;
//template<typename T1, typename T2,...,tepename Tn>
//返回值类型 函数名(参数列表)
template<typename T>
void Swap(T& a, T& b)
{
T temp = a;
a = b;
b = temp;
}
int mian()
{
int a = 2, b = 1;
Swap(a, b);
return 0;
}
函数模板的实例化
在使用不同类型的参数使用函数模板的时候,称为函数模板的实例化,模板参数实例化分为:隐式实例化和显式实例化
1.隐式实例化:让编译器根据实参推导模板参数的类型
cpp
#include <iostream>
using namespace std;
template<typename T>
T Add(T& a, T& b)
{
return a + b;
}
int main()
{
int a1 = 1, a2 = 2;
double b1 = 1.1, b2 = 2.2;
Add(a1, a2);
Add(b1, b2);
//下面这里是不可以的,第一个参数是int第二个参数是double,
// 一共就一个模板T,这个到底是int还是double是不明确的
// 所以我们可以强制类型转化/或者是显式实例化
//Add(a1, b1);
Add(a1,(int&)b1)
return 0;
}
2.显式实例化:在函数名的后面的<>中指定模板参数的类型
cpp
#include <iostream>
using namespace std;
template<typename T>
T Add(T& a, T& b)
{
return a + b;
}
int main()
{
int a1 = 1, a2 = 2;
double b1 = 1.1, b2 = 2.2;
Add(a1, a2);
Add(b1, b2);
//下面这里是不可以的,第一个参数是int第二个参数是double,
// 一共就一个模板T,这个到底是int还是double是不明确的
// 所以我们可以强制类型转化/或者是显式实例化
//Add(a1, b1);
Add(a1,(int&)b1);
int a = 10;
double b = 20.0;
///////////////////////
Add<double>(b1, b);
return 0;
}
模板函数的匹配
1.一个非函数模板可以和同名的函数模板同时存在,而且该函数还可以被实例化为这个非函数模板
2.对于非模板函数和同名函数模板,如果其他条件都相同,在调用时会优先调用非模板函数而不是从该模板产生出一个实例。如果模板可以产生一个更好的函数,那么会选择模板函数
3.模板函数不允许自动类型转化,但普通函数可以进行自动类型转化
cpp
#include <iostream>
using namespace std;
//专门处理int
int Add(int a, int b)
{
return a + b;
}
//通用
template<typename T>
T Add(T a, T b)
{
return a + b;
}
int main()
{
Add(1, 2);//调用第一个int类型的函数
Add<int>(1, 2);//调用T类型的函数
Add(1, 2.0);//模板函数可以生成更好的
return 0;
}
类模板
类模板的定义
cpp
template<class T1, class T2,...,class Tn>
class //类模板名
{
//类成员定义
};
例如
cpp
#include <iostream>
using namespace std;
//模板和声明不建议分离到两个文件.h和.cpp会导致链接错误
template<class T>
class A
{
public:
A(int a = 0)
:_a(a)
{}
private:
T _a;
};
int main()
{
return 0;
}
模板的实例化
模板实例化与函数模板实例化不同,类模板实例化需要在类模板名字后跟<>,然后将实例化的类型放在<>中就可以,类模板名字不是真正的了欸,而实例化后的结果才是真正的类。
cpp
//A是类名,A<int>才是类型
A<int> s1; // int
A<double> s2; // double