当前位置: 首页 > news >正文

C++之初识模版

1. 函数模板

1.1 函数模板概念及格式

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

我们来看下面两段代码,第二个代码只要通过template<typename T>就可以告诉编译器这个是需要你自己去推导的类型。然后我们就可以把参数的类型填为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<typename T>
void Swap( T& left, T& right) {T temp = left;left = right;right = temp; 
}

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

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

1.2 函数模板的原理

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

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

1.3 函数模板的实例化

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

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

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

1.4 模板参数的匹配原

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

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

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

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

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

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

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

int Add(int left, int right) {return left + right;
}template<class T1, class T2>
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<class T1, class T2>
T1 Add(T1 left, T2 right) {return left + right; 
}void Test()
{Add(1.1, 2.2);
}

2. 类模版

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

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

#include <iostream>
#include <string>
using namespace std;template <typename T>
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<int> Student1(11111,19,100);Student<double> Student2(22222.1,20.1,99.1);
}

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

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

相关文章:

  • 【Java高阶面经:微服务篇】4.大促生存法则:微服务降级实战与高可用架构设计
  • 掌握HTTPX:从基础到高并发工程实践
  • Lambda表达式的高级用法
  • 华为云Flexus+DeepSeek征文|华为云 Dify LLM 平台单机部署教程:一键开启高效开发之旅
  • 软件设计师“数据流图”真题考点分析——求三连
  • Devicenet主转Profinet网关助力改造焊接机器人系统智能升级
  • springboot3+vue3融合项目实战-大事件文章管理系统-文章分类也表查询(条件分页)
  • 自建srs实时视频服务器支持RTMP推流和拉流
  • 什么是 Agent 的 Message
  • IP地址详解
  • OOP和软件设计中的五大核心设计原则——SOLID原则
  • 用户有一个Django模型没有设置主键,现在需要设置主键。
  • 几种超声波芯片的特点和对比
  • day019-特殊符号、正则表达式与三剑客
  • 谈谈 Kotlin 中的构造方法,有哪些注意事项?
  • 算子窗口操作
  • apache http client连接池实现原理
  • Android车载应用开发:Kotlin与Automotive OS深度实践
  • vue好用插件
  • 大语言模型与人工智能:技术演进、生态重构与未来挑战
  • 什么伪原创网站好/电脑培训班一般要学多久
  • 网站建设报价明细表/东莞疫情最新数据
  • WordPress客服插件破解版/端点seo博客
  • 做网站陪聊下单/太原搜索排名提升
  • 购物网站建设要多少钱/电商网站建设 网站定制开发
  • 门户网站建设内容/it行业培训机构哪个好