前言
模板作为 C++ 的一大特色,对于泛型编程有着重要的作用。同时,对于大规模类似的函数或是类型不确定的类,模板都起了至关重要的作用。
一、模板
在开始学习模板之前,我们首先需要了解模板。先看下面一个例子:
#include <iostream>
using namespace std;
int func_one(int num){
return 2 * num;
}
double func_two(double num){
return 2 * num;
}
int main(){
int num_int = 2;
double num_double = 2;
func_one(num_int);
func_two(num_doule);
return 0;
}
我们可以轻易发现,对于函数 func_one、func_two,两者实现的功能基本相同,只是所接受的参数和返回值发生了对应的变化。因此有没有一种办法可以简化这两个函数,将其合并为一个呢?答案就是使用模板。
下面的例子是对上面的两个函数使用模板的结果:
#include <iostream>
using namespace std;
template <class T>
T func(T num){
return 2 * num;
}
int main(){
int num_int = 2;
double num_double = 2;
func(num_int);
func(num_doule);
return 0;
}
在上面的案例中我们见到了新的关键字 template。它表示此处运用模板,后面 <> 中则表示,有一个模板类型 T,T 在此会根据我们函数的传参自动生成对应的类型。例如 num_int 传入后 T 则代表 int; num_double 传入后 T 则代表 double。
模板就像一个空的模具,大体上不会改变,但是你提供什么参数都可以按照模具的形状进行操作。
二、函数模板
在上面介绍时我们使用的模板就是函数模板,除此之外还有类模板,但是我们先从函数模板开始讲起。
2.1 模板的格式
**函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型版本。**函数模板的诞生是为了简化重复的函数,哪怕利用重载,也需要对一个函数进行多次重载,但是模板函数只需一个模板即可适应各个种类。
函数模板的格式如下:
template <class T1, typename T2, class T3, … , typename TN>
返回值类型 函数名(参数列表){
函数主体;
}
声明一个模板类型的时候,可以使用 “class” 或 “typename”,两者无差别。但是需要注意的地方在于,一个模板类型只能代表一种类型。例如在上面的函数中,T1 实例化为 int 类型后就不能再代表 char 等类型,具体如下:
#include <iostream>
using namespace std;
template <class T1>
double func_one(T1 num_1, T1 num_2){
return num_1 + num_2;
}
template <class T1, class T2>
double func_two(T1 num_1, T2 num_2){
return num_1 + num_2;
}
int main(){
int num_int = 2;
double num_double = 2;
func_one(num_int, num_double);
func_two(num_doule, num_double);
return 0;
}
在这个例子中,主函数中调用 func_one 是失败的,T1 在接收 num_1 时,已经实例化为 int, 但是 num_2 为 double 类型,因此发生了错误。为接收不同类型的两个参数,我们可以考虑使用 func_two。
2.2 模板的匹配优先度
先看下面的案例,猜测系统会调用哪个函数。
#include <iostream>
using namespace std;
int func(int num_1, int num_2){
return num_1 + num_2;
}
template <class T1>
int func(T1 num_1, T1 num_2){
return num_1 + num_2;
}
int main(){
int num_1 = 1;
int num_2 = 2;
func(num_1, num_2);
func<int>(num_1, num_2);
return 0;
}
经过调试,我们可以得知:
第一次调用 func 函数,调用的是第一个非模板的 func 函数,这是由于在可以找到匹配的函数时,优先不调用模板函数,避免重复生成一个一样的函数;
第二次调用 func 函数,调用的模板生成函数,这是由于 func(), 表示我们手动要求生成一个 func 模板函数用 int 实例化之后的函数,此时会优先采用手动要求的模板函数。
2.3 模板的声明
比起其他的函数,模板函数要求必须声明和定义在一起,不可声明与定义分离。此过程涉及到编译链接的过程,不在此展开。
三、类模板
在了解了函数模板之后,类模板也非常好理解,例如我们之后会学到的 vector 容器就是一个模板类:
#include <iostream>
using namespace std;
template <class T>
class vector{
private:
T* ptr;
public:
vector(T num){
// ......
}
}
在这个类中,构造一个类时需要传入一个类型作为参数,然后 ptr 的类型就确定了,之后的函数就可以据此继续完成。之后将以 vector 为例,讲述一个模板类的实现。
四、总结
模板的优点显而易见,一方面节省了资源,便于代码的迭代更新,另一方面增加了代码的灵活性。那是不是我们要多多使用模板呢?答案是否定的。文章来源:https://www.toymoban.com/news/detail-699232.html
首先模板相比于普通的函数需要的编译时间更长,且出现错误信息时不易定位错误位置。所以具体使用重载还是模板要根据实际情况来合理进行判断选取。文章来源地址https://www.toymoban.com/news/detail-699232.html
到了这里,关于浅述C++模板——函数模板及类模板的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!