-------------------------------模板------------------------------------
前言: 在看本篇博客之前,我想先提出一个问题:以Add函数为例 但是看上述函数,我们能发现这个函数有什么不足? 很明显这个Add函数只能对整形数据进行处理,当我们想要对其他数据类型的数据进行处理的时候我们又有什么方法? 方法一:我们可以利用函数的重载对所有我们想要处理的数据类型进行重载 这是一个可行的方法,但是这个方法肉眼可见的麻烦,我们得把所有类型全部写一遍,那可真是把人写麻了!! 而且这个方法是能处理内置类型,如果用户自己创建了一个类型怎么办? 所以为了处理这种情况,C++的大佬为我们提供了简便方法
——————————————模板—————————————
举个简单的例子:钢铁厂有做狗饭盆的模具,小明委托钢铁厂给自己的狗旺财做个一饭盆,如果小明家没有钱,那他给钢铁厂提供不锈钢作为材料,那旺财只有一个不锈钢饭盆可以用;如果小明家是小康家庭,提供了铁,那么旺财就拥有一个铁饭碗;如果小明很爱旺财,给钢铁厂的是金子,那么旺财就是拥有金饭盆的勾勾了!!!
如果在C++中,也能够存在这样一个模具,通过给这个模具中填充不同材料(类型),来获得不同材料的铸件(生成具体类型的代码),我们能少掉多少头发啊!!!!! 幸运的是我们的前辈们在掉了不少头发之后为我们提供了模板。
模板分为了两类: 我们将主要对这两种模板进行介绍。
1、函数模板
1.1什么是函数模板?
函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型版本。
1.2函数模板格式
以Add函数为例: 注:typename是用来定义模板参数关键字,也可以使用class(切记:不能使用struct代替class)
对比两个函数我们发现,在使用template关键字后我们在<>内写的代码可以理解为告诉编译器 “ T ” 是数据类型,那么在编译器对下面的模板函数进行编译时,会对T进行相对的替换。 ///
函数模板是一个蓝图,它本身并不是函数,是编译器用使用方式产生特定具体类型函数的模具。所以其实模板就是将本来应该我们做的重复的事情交给了编译器。 ///
2.3模板调用原理
在函数运行之前,编译器需要先对代码进行编译,在编译阶段,对于模板有两种实例化方式: ①:如果是隐式实例化:让编译器根据实参推演模板参数的实际类型 编译器会对传递的实参的类型进行推演,然后确定模板参数列表中T的实际类型,确定出来后再根据确定的类型生成实际类型的代码。
例:Add(1,2) 左:int 右:int ---------->生成:int Add< int >
②:显示实例化:在函数名后的<>中指定模板参数的实际类型 如果类型不匹配,编译器会尝试进行隐式类型转换,如果无法转换成功编译器将会报错。 例:Add< int >(1,2)
2.4模板函数的匹配原则
①: 一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这个非模板函数
②:对于非模板函数和同名函数模板,如果其他条件都相同,在调动时会优先调用非模板函数而不会从该模板产生出一个实例。如果模板可以产生一个具有更好匹配的函数, 那么将选择模板
③: 模板函数不允许自动类型转换,但普通函数可以进行自动类型转换
2、类模板
在学习了函数模板之后,我们再进型类模板的学习就会简单很多。 举一个简单的例子:我们之前肯定都接触过数据结构的顺序表,我们先用普通的类实现一个顺序表。 在以前我们想要将顺序表类型更改我们需要使用typedef,方便我们随时对数据类型进行修改,但是这种方法也有隐患,现在我们学习了模板之后我们只需要在类前加上template< class T >并将类中Datatype修改为T即可。
2.1 类模板的实例化
类模板实例化与函数模板实例化不同,类模板实例化需要在类模板名字后跟<>,然后将实例化的类型放在<>中即可,类模板名字不是真正的类,而实例化的结果才是真正的类。
Vector类名,Vector< int >才是类型
Vector< int > s1;
Vector< double > s2;
总结
|