这篇文章主要介绍了c++泛型编程基本概念的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获、下面让小编带着大家一起了解一下。
1。什么是泛型编程?
比如说,我们如何实现一个通用的交换函数呢? int型,双型、字符型的交换
void 交换(int&,,, int&,右) { int temp =,离开; 时间=left ; 时间=right 温度; } void 交换(double&,,, double&,右) { double temp =,离开; 时间=left ; 时间=right 温度; } void 交换(char&,,, char&,右) { char temp =,离开; 时间=left ; 时间=right 温度; } …
虽然我们可以使用函数重载来实现,但是有一下几个不好的地方:
(1)重载的函数仅仅只是类型不同,代码的复用率比较低,当新类型出现时,就需要增加对应的函数。
(2)代码的可维护性比较低,一个出错可能所有的重载均出错。
泛型编程:编写与类型无关的通用代码,是代码复用的一种手段。
模板是泛型编程的基础。包括函数模板和类模板。
前面我们介绍的向量,列表,地图都是一种数据结构容器,
容器本身的存储结构不同,各容器中存在的数据类型也可以不同。
但我们在访问这些容器中数据时,拥有相同的方式。
这种方式就叫做“泛型编程”,顾名思义,不同的类型采用相同的方式来操作。
2。函数模板
(1)函数模板概念
函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型版本。
(2)函数模板格式
template返回值类型,函数名(参数列表){}//typename是用来定义模板参数关键字,也可以使用类(切记:不能使用结构体代替类)
templatevoid 交换(T&, left ,, T&,右) { T temp =,离开; 时间=left ; 时间=right 温度; }
(3)函数模板的原理
函数模板是一个蓝图,它本身并不是函数,是编译器通过使用方式产生特定具体类型函数的模具。所以其实模板就是将本来应该我们做的重复的事情交给了编译器。
在编译器编译阶段,对于函数模板的使用,编译器需要根据传入的实参类型来推演生成对应类型的函数以供调用。比如:当用两类型使用函数模板时,编译器通过对实参类型的推演,将T确定为两类型,然后产生一份专门处理两类型的代码,对于字符类型也是如此。
(4)函数模板的实例化
用不同类型的参数使用函数模板时,称为函数模板的实例化。
模板参数实例化分为:隐式实例化和显式实例化。
1)隐式实例化:让编译器根据实参推演模板参数的实际类型
templateT 添加(const T&,,, const T&,右) { return left  +,正确的; } int main () { int a1 =, 10日,a2 =, 20; 10.0 double d1 =,,, d2 =, 20.0; 添加(a1, a2); 添加(d1, d2);/* 添加(a1, d1); 该语句不能通过编译,因为在编译期间,当编译器看到该实例化时,需要推演其实参类型 通过实参a1将T推演为int,通过实参d1将T推演为两类型,但模板参数列表中只有一个T, 编译器无法确定此处到底该将T确定为int 或者,两类型而报的错 注意:在模板中,编译器一般不会进行类型转换操作,因为一旦转化出问题,编译器就需要背黑锅 *///,此时有两种处理方式:1只,用户自己来强制转化,2只使用显式实例化 Add (a1,, (int) d1); return 0; }
2)显式实例化:在函数名后的& lt;祝辞中指定模板参数的实际类型
int 主要(空白) { int a =, 10; double b =, 20.0;//,显式实例化 Add(a, b); return 0;//如果类型不匹配,编译器会尝试进行隐式类型转换,如果无法转换成功编译器将会报的错。 }
(5)模板参数的匹配原则
1)一个非模板函数可以和一个同名的模板函数同时存在,而且该函数模板还可以被实例化为这个非模板函数。