1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > 【C++】模板-函数模板 类模板

【C++】模板-函数模板 类模板

时间:2020-12-18 13:26:00

相关推荐

【C++】模板-函数模板 类模板

文章目录

泛型编程函数模板函数模板的原理函数模板的实例化模板参数的匹配原则类模板类模板的定义格式类模板的实例化

泛型编程

如果我们想要实现一个通用的交换函数,我们可以通过函数重载来实现,这些重载函数唯一的区别就是函数参数的类型不一样,虽然可以满足我们的需求,但是也有不好的地方:

1、重载的函数仅仅只是类型不同,代码的复用率比较低,只要有新类型出现时,就需要增加对应的函数

2、代码的可维护性比较低,一个出错可能所有的重载都出错。

为了解决上述问题,C++提出了泛型编程,就是编写与类型无关的通用代码,是代码复用的一种手段,模板是泛型编程的基础。

函数模板

函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型版本,就是模板函数。

函数模板格式

template <typename T1,typename T2,…,typename Tn>

返回值类型 函数名(参数列表){}

template<typename Type>Type Max(Type a, Type b){return a > b ? a : b;}

typename是用来定义模板参数的关键字,也可以使用class,推荐使用typename,但是不能用struct代替class。

函数模板的原理

函数模板本身并不是一个函数,它只是一个蓝图,是编译器产生特定具体类型函数的模具,模板只是将本来应该由程序员做的那部分重复的工作交给了编译器来完成。

在编译器编译阶段,编译器会根据传入的实参类型来推演生成对应类型的模板函数。比如,我们判断double类型数据的Max时,编译器通过对实参类型的推演,将Type确定为double类型,然后会产生一份专门处理double类型数据的函数,对于其他类型也是如此,编译器帮我们完成了大量重复的工作。

函数模板的实例化

用不同类型的参数使用函数模板时,称为函数模板的实例化,函数模板的实例化分为:隐式实例化和显式实例化。

隐式实例化:让编译器根据实参类型推演模板参数的实际类型

template<typename Type>Type Max(Type a, Type b){return a > b ? a : b;}void main(){Max(10, 13.24);}

Type无法确定自己是int类型还是double类型,这种情况下也不支持隐式转换,类型无法统一,产生了二义性,无法正常执行代码。

这种情况可以有下面的解决办法:

1、用户自己来强制转化

template<typename Type>Type Max(Type a, Type b){return a > b ? a : b;}void main(){Max((double)10, 13.24);}

或者是:

template<typename Type>Type Max(Type a, Type b){return a > b ? a : b;}void main(){Max(10, (int)13.24);}

上面这两种都是通过实参的推演得出Type的类型。

2、使用显式实例化:在函数后面的<>中指模板参数的实际类型

template<typename Type>Type Max(Type a, Type b){return a > b ? a : b;}void main(){Max<int>(10, 13.24);}

明确告诉Max模板的参数类型是int,这个时候,传递的实参类型不满足int就会进行隐式类型,转化如果无法转换成功编译器将会报错。

3、增加模板参数的个数

template<typename Type1,typename Type2>Type1 Max(Type1 a, Type2 b){return a > b ? a : b;}void main(){cout << Max(10, 13.24) << endl;}

这样编译器根据实参推演模板参数的实际类型就互相不打扰了,int匹配Type1,double匹配Type2,也能够解决问题。

模板参数的匹配原则

1、一个非模板函数可以和一个同名的模板函数同时存在,而且该模板函数还可以被实例化为这个非模板函数

template<typename Type>Type Max(const Type &a, const Type &b){return a > b ? a : b;}int Max(const int &a, const int &b){return a > b ? a : b;}void main(){cout << Max(10, 13) << endl;//调用非模板函数cout << Max<int>(10, 13) << endl;//调用模板函数实例化出的函数}

2、对于非模板函数和同名函数模板,如果其他条件都相同,在调用时会优先调用非模板函数,不会从该函数模板实例化出一个模板函数。如果函数模板可以实例化出一个更加匹配的模板函数,那么将会选择实例化出一个模板函数来完成功能。

ype2 Max(const Type &a, const Type2 &b){return a > b ? a : b;}int Max(const int &a, const int &b){return a > b ? a : b;}void main(){cout << Max(10, 13) << endl;//与非模板函数完全匹配,不需要函数模板实例化cout << Max(10, 13.98) << endl;//函数模板可以实力换出一个更加匹配的版本,编译器根据实参推演出参数实际类型,生成一个更匹配的函数}

3、模板函数不允许自动类型转换,但是普通函数可以进行自动类型转换。

template<typename Type>Type Max(const Type &a, const Type &b){return a > b ? a : b;}int Max(const int &a, const int &b){return a > b ? a : b;}void main(){cout << Max(10, 13) << endl;cout << Max(10, 13.98) << endl;}

这种情况下,都会调用非模板函数,起码可以保证正常执行。

类模板

类模板的定义格式

template<typename T1,typename T2,…typename T3>

class 类模板名

{

//类内成员定义

};

类模板中的函数都是函数模板,放在类外进行定义时,需要加模板参数列表。如下所示:

template<typename Type1, typename Type2 = int>//具备默认参数class Seqlist{public:void push_back(const Type1 &v);public:enum{DEFAULT_SEQLIST_SIZE=8};private:Type1 *base;size_t capacity;size_t size;};template<typename Type1,typename Type2>void Seqlist<Type1,Type2>::push_back(const Type1 &v){}

类模板的实例化

类模板的实例化和函数模板的实例化不相同,类模板的实例化需要在类模板名字后面加上<>,然后实例化的类型放在<>中即可,函数模板可以推演类型,但是类模板必须明确类模板参数的类型,类模板名字不是真正的类,实例化的结果才是真正的类,,实例化之后的类才能够实例化出对象。

//Seqlist是类名,Seqlist<int>才是类型Seqlist<int> s1;Seqlist<double> s2;

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。