【C++学习笔记】模板(一)

模板的概念

模板是实现代码复用的一种手段,是C++重要的特征之一此前在定义函数与类时,必须明确指明其中用到的变量的数据类型。如果需要对不同类型的数据进行相同的处理,就需要重新定义函数或者类。

我们知道函数是一种代码复用的方式,通过定义不同的函数实现不同的操作,但是函数有一个问题,就是每次定义函数要指定数据类型,这在普通的函数中当然没关系,但是,如果我需要对不同的数据进行相同的操作时,在没有模板时,我们就需要对函数进行多次重载,这就大大降低了编程效率,为解决这个问题,就有了模板的概念。

模板提供了函数与类的“参数化设计”的方法——将其中某些形参、变量、返回值类型用模板参数替代,生成函数模板或类模板;编译系统通过模板来生成函数。

我之前把函数或类比喻成一个工具(比如锤子、锯子等),函数或类模板其实可以比喻成工厂生产锤子或者锯子的模具或者设计图,我们有时候需要得工具太多了,一把把类似的工具带出来太麻烦了,那么就干脆定义一个设计图或者模具,让工厂(编译器)自己去生产吧。

int max(int x,int y)
{
	return (x>y)? x:y;
}
float max(float x,float y)
{
return (x>y)? x:y;
}
double max(double x, double y)
{
return (x>y)? x:y;
}
//太麻烦了!可以整合为:
template <class T> //定义函数模板
T max(T x,T y)
{
	return(x>y)? x:y;
	}


函数模板

函数模板的声明:

template <class 类型参数>
//----------------------------------说明一个“虚拟类型”---------------------------
返回类型 函数名(模板形参表)
{
	函数体
	}
//--------------------------------利用这个虚拟类型进行定义函数--------------------------
或:
template <typename 类型参数>
返回类型 函数名(模板形参表)
{
	函数体
}
//实例:
#include<iostream>
using namespace std;
template <class T> //定义函数模板
T Max(T x,T y)
{
    cout<<"max1 is used"<<endl;
    return(x>y)? x:y;
    
}
template<class T, class K>
T Max(T x, K y)
{
    cout<<"max2 is used"<<endl;
    return (x>T(y))? x:y;
    
}

int main()
{
    int x =1;
    double y =2.89;
    int z = 3;
    Max(x,y);
    Max(x,z);
    return 0;
}


怎么理解这段声明呢?
template: 是一个关键字,说明接下来我们要定义模板了。
<class 类型参数> :这相当于一个模子,就是实例中的“T”就告诉“工厂”(编译器):“我不知道函数中这个数据具体是什么类型,那我们就定义一个T类型好了,这个T类型具体是什么你工厂看到具体输入的实参后再决定吧。”
注意:前面“template<class 类型参数>”这条语句的作用范围只有一个模板,也就是说,你要定义几个模板,这条语句就要写几遍
T max(T x,Ty):
我们前面定义了一个“虚拟类型”T,接下来就是跟定义普通函数一样定义一个有“虚拟类型”的模板。
但要注意,虽然T这里没有确定的类型,但是在“T max(T x,T y)”语句中,参数x,y不管是什么数据类型,都必须保证x和y的类型是相同的。

注意,函数模板不是函数,是不对应可执行代码,只能算是一种描述,函数是函数模板的一个实例,只有系统需要函数时,才会根据这个模板生成相应的函数是,生成代码。假如系统不调用该函数,那么系统最后的代码中是没有模板中的代码的。
因此,一般模板都是写在.h文件中的,而不是写在.cpp文件中。
在这里插入图片描述

再看我给的实例,这个实例其实还有几个玄机:

#include<iostream>
using namespace std;
template <class T> //定义函数模板
T Max(T x,T y)
{
    cout<<"max1 is used"<<endl;
    return(x>y)? x:y;
    
}
template<class T, class K>
T Max(T x, K y)
{
    cout<<"max2 is used"<<endl;
    return (x>T(y))? x:y;
    
}
template <class T> //定义函数模板
T Max(T x,int y)
{
    cout<<"max3 is used"<<endl;
    return(x>y)? x:y;
    
}

int main()
{
    int x =1;
    double y =2.89;
    int z = 3;
    Max(x,y);
    //Max(x,z); 在执行这条语句时会报错
    return 0;
}

最后输出结果为:

max2 is used
max1 is used
Program ended with exit code: 0

1.定义模板后就不需要在开头定义函数了,模板在函数中的作用是接收参数,根据接收到参数的类型生产对应的函数。
2. 其实类型参数可以不止一个,当有多个类型参数时表明该函数模板生产的函数可能会接收不同类型的实参。这里加个可能表示如果只有这一个模板的情况下,就算模板接收的两个参数是一样的,也是没有关系的。但是,如果过类型参数只有一个,那就只能接收一种类型。
3. 函数模板是可以重载的,但是重载时“template<class 参数类型>”这个语句是不能省的。
4. 当模板接收的参数相同,且同时有相同参数模板(Max1)和不同参数模板(Max2)时,系统优先选择相同参数的函数模板。
5. 虽然T、K是虚拟的类型,但它具有类型的全部特征,也可以有自己对应的强制类型转换T()、K()。
6. 可以将自己定义的“虚拟类型”与已知的类型混用如max3一样。不过在实例中,在执行max(x,z)时会报错,这是因为此时系统是分不清到底要调用第一个Max函数模板还是第三个Max函数模板。如果我把x和z的类型改为float就不会有这个问题了。
7. template<class 参数类型> 声明 与下面的模板定义必须紧密连接在一起,中间不能有任何语句
8. 所有函数模板里的动作必须相同,也就是函数体必须相同,否则会报错。(你要是模板造出来的函数里面操作都不一样了,你还玩个毛的模板,定义函数重载去!)

函数模板与普通函数的关系

假如说一个程序中既有定义函数又有函数模板时,系统该怎么选取呢?
在这里插入图片描述
也就是说,编译器“偏好类型匹配,偏好函数”。如果用工具的例子继续类比的话就是“最匹配最合适的工具总是最好的。而在合适的工具中,私人订制的总比用模子生产出来的好。”

报错情况:

  1. 如果在调用完全匹配的函数时就有多个可用选择,系统会报错。
  2. 调用模板时有多个选择,系统会报错(这就是上面例子中Max(x,z); 会报错的原因。)
  3. 假如上述三个条件都不满足系统会报错。(注意:编译器不会强制类型转化来套用模板的,模板是比较死板的,不符合就是不符合。)

猜你喜欢

转载自blog.csdn.net/weixin_43819313/article/details/85107036