C++之初识模版

06-02 1246阅读

1. 函数模板

1.1 函数模板概念及格式

我们前面学过在面对同一种计算方式不同类型的时候,我们可以使用函数重载,但是这种方式又太过复杂,所以我们今天要学习泛型编程。简单来说,就是告诉编译器自己去推导类型。

我们来看下面两段代码,第二个代码只要通过template就可以告诉编译器这个是需要你自己去推导的类型。然后我们就可以把参数的类型填为T。

void Swap(int& left, int& right) {
 int temp = left;
 left = right;
 right = temp; 
}
void Swap(double& left, double& right) {
 double temp = left;
 left = right;
 right = temp;
 }
void Swap(char& left, char& right) {
 char temp = left;
 left = right;
 right = temp; 
}
template
void Swap( T& left, T& right) {
 T temp = left;
 left = right;
 right = temp; 
}

注意:typename是用来定义模板参数关键字,也可以使用class(切记:不能使用struct代替class)。

PS:我们要注意,如果说我们在一份函数模版里面有多个不同类型的参数时,那么我们要写多个typedef,简单来说就是template。因为每一个typedef是在告诉编译器这个类型你自己推导,同时会固定下来这一种类型。

1.2 函数模板的原理

在原理上来说,函数模版就是把本来我们自己做的事情交给编译器去做。简单来说就是编译器根据我们传入函数的类型来自己生成不同的模版。

比如:当用double类型使用函数模板时,编译器通过对实参类型的推演,将T确定为double类型,然后产生一份专门处理double类型的代码。

1.3 函数模板的实例化

当编译器把T确定为一种类型然后生成一份专门一份代码的时候,这份代码就是这个函数模版的实例化。

实例化又分为隐式实例化和显式实例化。简单来说就是隐式实例化是让编译器完全自己推导,而显式实例化就是指定编译器推导为一个类型(就是在使用这个函数的时候再函数名后面加上你想要指定推导的类型,举个例子,Swap,如果说有多个typedef的话就要在里面写多个类型)。

PS:如果显式实例化的类型不匹配,编译器会尝试进行隐式类型转换,如果无法转换成功编译器将会报错。

1.4 模板参数的匹配原则

简单来说就是一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这个非模板函数。

我们来看下面这段代码在Test里面如果说是直接写add(1,2),那么匹配的就是第一个add函数,如果我们在Add后面加了一个,那么就是在告诉编译器我指定要使用第二个Add,而如果说是double类型的话那就是只可以使用第二个Add。

我们可以理解为一个判断,if有指定那就使用指定,else if和非模板函数契合就使用非模板函数,else的话就让系统自己调用函数模板。

int Add(int left, int right) {
 return left + right; 
}
template 
T Add(T left, T right) {
 return left + right; 
}
void Test()
{
 Add(1, 2); //1
 Add(1, 2); //2
 Add(1.1,2.2);//3
}

我们来看下面这个代码,各位觉得在这个Test里面的这个Add会是调用哪个函数呢?

答案是第一个Add,因为它更合适。因为编译器会把这个2.2变为2,然后进行计算,那么计算出的结果会是3。

这个涉及到隐式类型转换(和上面说的隐式实例化不是同一个东西),简单来说就是编译器直接把小数后面的东西给断掉。

int Add(int left, int right) {
 return left + right;
}
template
T1 Add(T1 left, T2 right) {
 return left + right; 
}
void Test()
{
 Add(1, 2.2);
}

我们再来看下面这个代码,各位觉得这回是调用哪个Add呢?

答案是第二个Add,最后计算出来的结果是3.3。这是由 C++ 的重载决议规则和模板实参推导机制共同决定的。

总结一下就是一句话:模板实参推导阶段不允许自动类型转换,但函数调用时允许对实参进行标准转换。

说大白话就是能非模板函数就使用非模板函数,不方便的话就使用模版函数。

int Add(int left, int right) {
 return left + right;
}
template
T1 Add(T1 left, T2 right) {
 return left + right; 
}
void Test()
{
 Add(1.1, 2.2);
}

2. 类模版

我们想一下,一个函数我们可以通过模版的方式来对它进行模板化使它可以实例化匹配各种参数,那么一个类是不是也可以通过这样的方式来使它可以根据不同的参数来实例化成不同类型的类。

我们来看下面这个类,我们便可以通过输入不同的值来进行初始化从而实例化为不同的类模版。

#include 
#include 
using namespace std;
template 
class Student {
public:
    Student(T _member, T _age, T _score) 
    :member(_member),
    age(_age),
    score(_score) 
    {}
private:
    T member;      
    T age;         
    T score;   
};
int main()
{
    Student Student1(11111,19,100);
    Student Student2(22222.1,20.1,99.1);
}

PS:Student不是具体的类,是编译器根据被实例化的类型生成具体类的模具。只有实例化候的结果也就是Studednt1和Student2才是类。

这个类模版的使用我们是一定要会的,因为在后面的STL库的实现中我们会经常使用到。

免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们。

相关阅读

目录[+]

取消
微信二维码
微信二维码
支付宝二维码