本文介绍C编程的另一个分支3354泛型编程,它与面向对象并列。本文主要介绍三个部分:函数模板、类模板和成员模板。有需要的可以参考一下。
:
目录
1.什么是泛型编程?2.函数模板(1)函数模板的概念(2)函数模板的格式(3)函数模板的原理(4)函数模板的实例化(5)模板参数的匹配原理(3)类模板(1)类模板的定义格式(2)类模板的实例化总结
1.什么是泛型编程?
例如,我们如何实现一个通用的交换函数?int、double和char类型的交换
void交换(int left,int right)
{
int temp=left
左=右;
右=temp
}
无效交换(双左、双右)
{
double temp=左;
左=右;
右=temp
}
无效交换(左字符,右字符)
{
char temp=left
左=右;
右=temp
}
.
虽然我们可以使用函数重载来实现它,但是有一些缺点:
(1)重载的函数只是类型不同,代码复用率比较低。当新的类型出现时,需要添加相应的功能。
(2)代码的可维护性比较低,一个错误就可能导致所有重载出错。
泛型编程:编写与类型无关的泛型代码是代码重用的一种手段。
模板是泛型编程的基础。包括函数模板和类模板。
我们前面介绍的vector、list、map都是数据结构容器。
容器本身的存储结构不同,所以每个容器中的数据类型可以不同。
但是当我们访问这些容器中的数据时,我们有相同的方法。
这种方法被称为“泛型编程”。顾名思义,不同类型的操作方式相同。
2.函数模板
(1)函数模板概念
函数模板表示一族函数,与类型无关,使用时参数化,从而根据实参类型生成函数的特定类型版本。
(2)函数模板格式
模板类型名T1,类型名T2,键入名称Tn
返回值类型函数名(参数列表){}
//typename是用来定义模板参数的关键字,也可以用class(记住:不能用struct代替class)
模板类型名称T
无效交换(T左,T右)
{
T temp=左;
左=右;
右=temp
}
(3)函数模板的原理
函数模板是一个蓝图,它本身不是函数,而是编译器通过使用它来生成特定类型函数的模具。所以其实模板就是把本该我们做的重复性的事情交给编译器。
在编译器的编译阶段,对于函数模板的使用,编译器需要根据传入的参数类型,推导生成相应类型的函数进行调用。比如函数模板和double type一起使用时,编译器通过对实参类型的推演,确定T为double类型,然后生成专门处理double类型的代码,对于字符类型也是如此。
(4)函数模板的实例化
当使用不同类型参数的函数模板时,称为函数模板的实例化。
模板实例化包括隐式实例化和显式实例化。
1)隐式实例化:让编译器根据实际实参推导出模板形参的实际类型。
模板类T
T相加(左常数,右常数)
{
向左向右返回;
}
int main()
{
int a1=10,a2=20
双d1=10.0,d2=20.0
Add(a1,a2);
Add(d1,D2);
/*
Add(a1,D1);
语句无法编译,因为在编译过程中,编译器看到实例化时,需要推导出它的参数类型。
T由实参a1推导为int,由实参d1推导为double,但模板形参列表中只有一个T。
编译器无法确定t在这里应该确定为int还是double类型,并报告错误。
注意:在模板中,编译器一般不进行类型转换,因为一旦转换出问题,编译器需要背黑锅。
*/
//此时有两种处理方式:1。用户自己强行改造;2.使用显式实例化。
Add(a1,(int)D1);
返回0;
}
2)显式实例化:在函数名后指定模板参数的实际类型。
int main(void)
{
int a=10
双b=20.0
//显式实例化
添加剂(a,b);
返回0;
//如果类型不匹配,编译器将尝试隐式类型转换。如果转换失败,编译器将报告错误。
}
(5)模板参数的匹配原则
1)非模板函数可以和同名的模板函数同时存在,函数模板也可以实例化为这个非模板函数。
Int Add(Int left,int right)///一个处理int的加法函数。
{
向左向右返回;
}
t//类通用加法函数
T加法(T左,T右)
{
向左向右返回;
}
无效测试()
{
添加(1,2);//与非模板函数匹配,编译器不需要专门化
Addint(1,2);//调用编译器专用化的添加版本
}
2)对于同名的非模板函数和模板函数,如果其他条件都相同,那么传递时会先调用非模板函数,不会从模板生成实例。如果模板能产生更好匹配的函数,那么该模板将被选中。
Int Add(Int left,int right)///一个处理int的加法函数。
{
向左向右返回;
}
Classt1,class T2//通用加法函数
T1相加(T1左,T2右)
{
向左向右返回;
}
无效测试()
{
添加(1,2);//与非函数模板类型完全匹配,不需要函数模板实例化。
添加(1,2.0);//模板函数可以生成更匹配的版本,编译器根据实参生成更匹配的Add函数。
数数
}
3.类模板
(1)类模板的定义格式
模板类T1,类T2,Tn类
类别模板名称
{
//类中成员的定义
};
//动态序列表
//注意:Vector不是具体的类,而是编译器根据实例化的类型生成具体类的模具。
模板类T
分类向量
{
公共:
向量(大小t容量=10)
:_pData(新T[容量])
,_size(0)
,_容量(容量)
{}
//演示如何使用析构函数:在类内声明,在类外定义。
~ Vector();
无效推回(常量数据);
void PopBack();
//.
Size _ t Size(){ return _ Size;}
测试运算符[](size_t pos)
{
assert(pos _ size);
return _ pData[pos];
}
私人:
T * _ pData
size _ t _ size
size _ t _ capacity
};
//注意:类模板中的函数在类外定义时,需要添加模板参数列表。
模板类T
Vector:~ Vector()
{
if(_pData)
delete[]_ pData;
_ size=_ capacity=0;
}
(2)类模板的实例化
类模板实例化不同于函数模板实例化。类模板实例化需要后跟类模板名称,然后可以将实例化的类型放入。类模板名不是真正的类,但实例化的结果是真正的类。
//Vector类名,Vectorint是类型
矢量S1;
Vectordouble s2
总结
本文到此为止。希望能帮到你,也希望你能多关注我们的更多内容!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。