前言

重载回顾完之后
虽然说让一个函数名有了多个功能,但是每次都要多写一个函数还是挺麻烦的。
而模板功能是为了提升复用性的功能。


引用

关键字:

  • template

正文

1
2
3
4
5
6
int Ave(int a, int b, int c){
return (a + b + c) / 3;
}
float Ave(float a, float b, float c){
return (a + b + c) / 3;
}

假如有这么个函数是求三个数的平均值,抛开类型,算法逻辑是相同的操作。重载也合理。
但是如果要对每一个类型都写一个这样的函数,就会变得很麻烦。

1
2
3
4
5
6
7
8
template <typename type> type Ave(type a, type b, type c){
return (a + b + c) / 3;
}
//或者template声明完模板后换行写也可以
template <typename type>
type Ave(type a, type b, type c){
return (a + b + c) / 3;
}

typename 后面跟的名称就像是自定义的关键词auto一般,后面写的函数使用这个变量名,就代表他是这个类型的函数

使用起来也很方便:
char类型也没问题,你用什么类型的参数他就会返回什么类型的值:

1
2
3
4
5
6
template <typename type> 
type Ave(type a, type b, type c){
type x = a + b;
type ch[10] = {0};
return (a + b + c) / 3;
}

既然说type是一个类型名,那么其实也可以在模板里面用它来定义变量。
甚至引用或者指针也ok。


指定模板类型

既然模板可以自适应,又为啥会用到指定?原因也就是形参类型不一的时候,没法主动去转换,需要人为干预。

1
2
3
4
5
6
7
8
template <typename type> 
type Ave(type a, type b, type c){
return (a + b + c) / 3;
}
int main(){
std::cout << Ave(26, 78.9f, 25.8f) << std::endl;
return 0;
}

当参数不一致的时候: 编译器就会给出错误提示
std::cout << Ave<int>(26, 78.9f, 25.8f) << std::endl;当指定类型之后:

能看到这个函数模板就变成int的类型的函数了。


指针引用

1
2
3
4
template<typename T>
T toMax(T a, T b){
return a > b ? a : b;
}

可看到被实例化成int*类型的函数了,但其实传递地址没有进行很好的处理,所以指很有可能是错的。

可当传递是引用时,发现并没有实例化成引用类型,而是普通的int类型。

而且const好像也不当回事:


函数模板重载

在经过一些例子尝试后,发现模板对于普通的类型转换是没有问题的,但是对于指针相关的操作可能就会有点不灵清。

就拿之前指针的问题,返回值甚至不是大的一方,只是单纯的返回了a。

解决的方法就是针对模板之外的情况附带一个指定的:

1
2
3
4
5
6
7
8
template<typename T>
T toMax(T a, T b){
return a > b ? a : b;
}
template<>
int *toMax(int *a, int *b){
return *a > *b ? a : b;
}

可以看到输出正常了,也匹配到了后面指针那个模板:

但是倒霉的又来了,我们这里的指针函数是int类型的,就失去了模板之前自动根据参数识别的情况,但是可以用函数重载去弥补一些损失

1
2
3
4
5
6
7
8
9
10
template<typename T>
T toMax(T a, T b){
return a > b ? a : b;
}
int *toMax(int *a, int *b){
return *a > *b ? a : b;
}
float *toMax(float *a, float *b){
return *a > *b ? a : b;
}

重载的时候就到了,不过要记住优先级,函数重载的优先级大于函数模板

1
2
3
4
5
6
7
8
9
10
template<typename T>
T toMax(T a, T b){
return a > b ? a : b;
}
int toMax(int a, int b){
return a > b ? a : b;
}
int *toMax(int *a, int *b){
return *a > *b ? a : b;
}

不相信的就自己动手,看看匹配到了那个:

如果是模板的话函数名后会有一个<>符号去匹配类型:


然后就是模板的重载,函数的重载是通过参数比较的,模板是否也相同

1
2
3
4
5
6
7
8
template <typename type> 
type Ave(type a, type b, type c){
return (a + b + c) / 3;
}
template <typename type>
type Ave(type a, type b, type c){
return (a + b + c) / 3;
}

报错来得很快,直接说他重复了。
我们将其变化一下:

1
2
3
4
5
6
7
8
template <typename type> 
type Ave(type a, type b, type c){
return (a + b + c) / 3;
}
template <typename type>
type Ave(type a, type b, ){
return (a + b ) / 2;
}

可以看到调用的时候明显就区分开了:


结语

函数重载能理解,模板重载就没啥太大问题,性质差不多。除了模板还有个例外情况可以写。