
目录
前言:
在C语言中我们经常要写一些雷同的函数,因为要和不同的参数去匹配,这就导致了我们的代码可读性不高,以及不太简洁。那么C++为了应对这种情况加入了一个新的概念模板。下面就让我来给大家详细介绍一下把。
一.泛型编程
首先在讲模板的时候我们要了解一下什么是泛型编程,回想一下我们在C语言中是怎么实现一个交换函数的或者在C++没有学习模板的时候是如何写一个全类型的交换函数的。这时候可能回想到函数重载,比如这样:
cpp
void Swap(int& a, int& b)
{
int tem = a;
a = b;
b = tem;
}
void Swap(double& a, double& b)
{
double tem = a;
a = b;
b = tem;
}
void Swap(char& a, char& b)
{
char tem = a;
a = b;
b = tem;
}
这样写不仅过于麻烦,还打打降低的代码的可读性以及简洁性。那么我们可不可以像活版印刷那样创建一个模板呢?当我们需要时直接利用模板就可以实现出来。
那么下面就用到了我们的模板。
模板大致分为两类函数模板以及类模板,下面让我来为大家详细的介绍一下。
二.函数模板
概念:
函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型版本。
1.函数模板格式
那么我们要怎么去用我们的函数模板呢?
template<typename 变量名1,typename 变量名2,.....,typename 变量名n>
当然还有其他的表示方法比如:
template<class 变量名1,class 变量名2,.....,class 变量名n>
一般来说我们更喜欢使用class来表示,当然两者也可以混用,但是并不建议这么做因为这降低了代码的可读性。
2.函数模板的使用
那们我们的函数模板应该要怎么使用呢?
cpp
template<class T>
//template<typename T>
void Swap(T& a, T& b)
{
T tem = a;
a = b;
b = tem;
}
int main()
{
int a = 2, b = 3;
double a1 = 2.1, b1 = 3.1;
Swap(a, b);
Swap(a1, b1);
cout << a << ' ' << b << ' ' << endl;
cout << a1 << ' ' << b1 << ' ' << endl;
return 0;
}
可以看到虽然两组变量的类型不同但还是依靠一个Swap函数完成了任务。模板的出现使得我们的编程更加方便,称为泛型编程。那们上面都是我们内置类型的例子,我们的自定义类型能不能很好的完成任务呢?我们不妨来试一下:
cpp
template<class T>
//template<typename T>
void Swap(T& a, T& b)
{
T tem = a;
a = b;
b = tem;
}
class date {
public:
date(int year=0,int month=0,int day=0)
:_year(year)
,_month(month)
,_day(day)
{}
void Print()
{
cout << _year << ' ' << _month << ' '<<_day << endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
date a(2005, 10, 1);
date b(2000, 5, 1);
a.Print();
b.Print();
Swap(a, b);
a.Print();
b.Print();
return 0;
}
可以发现依旧可以完成我们的任务。
3.函数模拟板的实例化
我们思考一个问题,如果两个变量传的类型不一样那们我们应该怎么办呢?或者是说这时候我们的交换函数应该要怎么运行呢?

可以发现我们的程序并不能够运行,这是因为函数模板只是给了编译器一个参考,这并不是一个可以直接调用的函数,我们的编译器会根据我们所传的参数来决定这个函数。当我们传入不同的参数时编译器会分不清我们需要什么,所以并不能够执行,我们可以观察底层的汇编语言来证明:

那么对于这种情况我们有什么解决办法呢?
一种方法是我们自己进行强制类型转换:
cpp
template<class T>
T Add(T a, T b)
{
return a + b;
}
int main()
{
int a = 1;
double b = 2.2;
cout << Add(a,(int) b) << endl;
cout << Add((double)a,b) << endl;
}

另一种方法就是我们的实例化了,简单来说就是确定这个函数的参数类型。
cpp
template<class T>
T Add(T a, T b)
{
return a + b;
}
int main()
{
int a = 1;
double b = 2.2;
cout<<Add<double>(a, b)<<endl;
}

那么就有同学要继续问了有没有一种更加方便的方法?
有的兄弟,有的。像这么简单又强势的方法只有1个了(博主所知道的)。这个方法不用每次调用时都去设置:
cpp
template<class T1,class T2>
auto Add(T1 a, T2 b)
{
return a + b;
}
int main()
{
int a = 1;
double b = 2.2;
cout << Add(a, b) << endl;
}
不过这种方法就只能遵循隐式类型转换了,并不能够自由选择自己所需要的类型。
三.类模板
类模板与函数模板相似,不一样的一点就是由于模板无法检测到返回函数,所以类模板进行定义的时候只能使用实例化。
cpp
template<class T>
class Date {
public:
Date(T year=0, T month=0, T day=0)
:_year(year)
, _month(month)
, _day(day)
{}
void Print()
{
cout << _year << ' ' << _month << ' '<<_day << endl;
}
private:
T _year;
T _month;
T _day;
};
int main()
{
Date <int>D(2004, 10, 01);
D.Print();
Date <double>D1(2004.1, 10.1, 01.1);
D1.Print();
return 0;
}
同时需要注意的是当在类模板中进行函数声明和定义分离的时候仍需要调用模板列表:
cpp
template<class T>
class Date {
public:
Date(T yea=0, T month=0, T day=0);
void Print()
{
cout << _year << ' ' << _month << ' ' << _day << endl;
}
private:
T _year;
T _month;
T _day;
};
template<class T>
Date<T>::Date(T year , T month , T day)
:_year(year)
, _month(month)
, _day(day)
{}
int main()
{
Date <int>D(2004, 10, 01);
D.Print();
Date <double>D1(2004.1, 10.1, 01.1);
D1.Print();
return 0;
}
结言:
今天我们详细的介绍了一下泛型编程,函数模板以及类模板的使用,当然模板的作用并不止步于此。这些只是最为基础的应用,在后期我们还会学到更加厉害的代码。感兴趣的可以关注一下博主哦,我们一起进步!