C++模版

文章目录

  • C++模版
    • 1、泛型编程
    • 2、函数模版
      • 2.1、函数模版概念
      • 2.2、函数模版格式
      • 2.3、函数模版原理
      • 2.4、函数模版的实例化
      • 2.5、模板参数的匹配原则
    • 3、类模版
      • 3.1、类模版概念
      • 3.2、类模版格式
      • 3.3、类模板的实例化

img

C++模版

1、泛型编程

  • 泛型编程(Generic Programming)是一种编程范式,它强调编写可以在不同数据类型上工作的通用代码。泛型编程的目标是编写更具通用性和复用性的代码,以减少代码的重复编写,并提高代码的可维护性。

    泛型编程的主要特点包括:

    1. 通用性: 泛型编程的代码不依赖于特定的数据类型,而是能够在多种不同数据类型上工作。这使得代码更具通用性。
    2. 类型参数化: 泛型编程通过参数化类型,允许在代码中使用参数化类型的变量、函数或类。这意味着你可以编写一次通用代码,然后在不同的上下文中使用不同的类型。
    3. 类型安全: 泛型编程强调类型安全,因为它在编译时进行类型检查,避免了运行时的类型错误。
    4. 代码复用: 泛型代码可以在不同的场景中重复使用,减少了代码的冗余。

    如何实现一个通用的交换函数呢 ?

    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;
    }
    
    //......
    int main() {
        int a = 1, b = 2;
        double c = 1.1, d = 2.2;
        Swap(a, b);
        Swap(c, d);
        return 0;
    }
    

    使用函数重载虽然可以实现,但是有以下几个不好的地方:

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

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

    那能否告诉编译器一个模子,让编译器根据不同的类型利用该模子来生成代码呢?

    答:C++里面有一种机制 — 模版(函数模版和类模版)

    泛型编程:编写与类型无关的通用代码,是代码复用的一种手段。模板是泛型编程的基础。


2、函数模版

2.1、函数模版概念

  • 函数模板(Function Template)是C++中的一种机制,允许你编写可以应用于不同数据类型的通用函数。函数模板允许你编写一次通用函数定义,然后可以将不同的数据类型作为参数传递给该函数,从而自动生成特定数据类型的函数实例。

    函数模板的基本概念包括:

    1. 通用性: 函数模板允许你编写通用函数,不限于特定数据类型。这使得代码更具通用性和复用性。
    2. 类型参数: 函数模板通过使用类型参数(通常用typenameclass关键字指定)来表示可以应用于不同数据类型的函数。
    3. 实例化: 当你调用函数模板并传递特定数据类型时,编译器会根据传递的数据类型生成特定数据类型的函数实例。这个过程称为实例化
    4. 类型推导: C++编译器通常能够从传递的参数==推断==出要使用的数据类型,从而实例化函数模板。

2.2、函数模版格式

  • 格式:template<typename T1, typename T2,......,typename Tn>

  • 举例:

    • 单参数函数模版

      template<typename T>
      
      void Swap(T &a, T &b) {
          T tmp = a;
          a = b;
          b = tmp;
      }
      
      int main() {
          int a = 1, b = 2;
          double c = 1.1, d = 2.2;
          Swap(a, b);
          Swap(c, d);
          return 0;
      }
      
    • 多参数函数模版

      template<typename T1, class T2>
      
      void Swap(T1 &a, T2 &b) {
          T1 tmp = a;
          a = b;
          b = tmp;
      }
      
      int main() {
          int a = 1, b = 2;
          double c = 1.1, d = 2.2;
          Swap(a, b);
          Swap(c, d);
          Swap(a, c);
          return 0;
      }
      
    • 注意:typename是用来定义模板参数关键字,也可以使用class(切记:不能使用struct代替class)。

2.3、函数模版原理

  • 函数模板是一个蓝图,它本身并不是函数,是编译器用使用方式产生特定具体类型函数的模具。所以其实模板就是将本来应该我们做的重复的事情交给了编译器。

  • 在编译器编译阶段,对于模板函数的使用,编译器需要根据传入的实参类型来推演生成对应类型的函数以供调用。比如:当用double类型使用函数模板时,编译器通过对实参类型的推演,将T确定为double类型,然后产生一份专门处理double类型的代码,对于字符类型也是如此。

  • 注意:这三次调用的Swap不是同一个函数

    • 我们vs转到反汇编来看函数地址

2.4、函数模版的实例化

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

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

    template<class T>
    
    T Add(const T &left, const T &right) {
        return left + right;
    }
    
    int main() {
        int a1 = 10, a2 = 20;
        double d1 = 10.0, d2 = 20.0;
        Add(a1, a2);//推导出a1,a2是int类型
        Add(d1, d2);//推导出d1,d2是double类型
    
        /*
        该语句不能通过编译,因为在编译期间,当编译器看到该实例化时,需要推演其实参类型
        通过实参a1将T推演为int,通过实参d1将T推演为double类型,但模板参数列表中只有一个T,
        编译器无法确定此处到底该将T确定为int 或者 double类型而报错
        注意:在模板中,编译器一般不会进行类型转换操作,因为一旦转化出问题,编译器就需要背黑锅
        Add(a1, d1);
        */
    
        // 此时有两种处理方式:1. 用户自己来强制转化 2. 使用显式实例化
        //1. 用户自己来强制转化 (隐式实例化)
        int a = 1;
        double d = 2.1;
        Add(a, (int) d);
    
        //2. 使用显式实例化
        int b = 1;
        double c = 2.1;
        Add<int>(b, c);//这里c就被强转化为int类型
        return 0;
    }
    
  • 显式实例化在函数名后的<>中指定模板参数的实际类型

    template<class T>
    
    T Add(const T &left, const T &right) {
        return left + right;
    }
    
    int main() {
      	int b = 1;
        double c = 2.1;
        Add<double>(b, c);//这里b就被强转化为double类型
        return 0;
    }
    
    • 函数参数里如果没有模版则需要显式实例化

      template<class T>
      
      T Add(const int &left, const int &right) {
          T sum = left + right;
          return sum;
      }
      
      int main() {
          
          int b = 1;
          double c = 2.1;
          int a = Add<int>(b, c);//这里b就被强转化为double类型
      
          return 0;
      }
      

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

2.5、模板参数的匹配原则

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

    // 专门处理int的加法函数
    int Add(int left, int right) {
        return left + right;
    }
    
    // 通用加法函数
    template<class T>
    T Add(T left, T right) {
        return left + right;
    }
    
    int main() {
        Add(1, 2); // 与非模板函数匹配,编译器不需要特化
        Add<int>(1, 2); // 调用编译器特化的Add版本
        return 0;
    }
    

  2. 对于非模板函数和同名函数模板,如果其他条件都相同,在调动时会优先调用非模板函数而不会从该模板产生出一个实例。如果模板可以产生一个具有更好匹配的函数, 那么将选择模板

    // 专门处理int的加法函数
    int Add(int left, int right) {
        return left + right;
    }
    
    // 通用加法函数
    template<class T1, class T2>
    T1 Add(T1 left, T2 right) {
        return left + right;
    }
    
    int main() {
        Add(1, 2); // 与非函数模板类型完全匹配,不需要函数模板实例化
        Add(1, 2.0); // 模板函数可以生成更加匹配的版本,编译器根据实参生成更加匹配的Add函数
        return 0;
    }
    

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


3、类模版

3.1、类模版概念

  • 类模板(Class Template)是C++中的一种机制,允许你定义通用类,其中的数据成员和成员函数可以适用于不同的数据类型。类模板允许你编写一次通用类定义,然后可以将不同的数据类型作为模板参数传递给该类,从而自动生成特定数据类型的类实例

    类模板的基本概念包括:

    1. 通用性: 类模板允许你编写通用类,不限于特定数据类型。这使得代码更具通用性和复用性。
    2. 类型参数: 类模板通过使用类型参数(通常用typenameclass关键字指定)来表示可以应用于不同数据类型的类。
    3. 实例化: 当你创建类模板的对象时,编译器会根据传递的数据类型生成特定数据类型的类实例。这个过程称为实例化。
    4. 类型推导: C++编译器通常能够从传递的参数==推断==出要使用的数据类型,从而实例化类模板。

3.2、类模版格式

  • 格式:

    template<class T1, class T2, ..., class Tn>
    class 类模板名
    {
    	 // 类内成员定义
    };
    
  • 举例:

    // 动态顺序表
    // 注意:Vector不是具体的类,是编译器根据被实例化的类型生成具体类的模具
    template<class T>
    class Vector {
    public :
        Vector(size_t capacity = 10)
                : _pData(new T[capacity]), _size(0), _capacity(capacity) {}
    
        // 使用析构函数演示:在类中声明,在类外定义。
        ~Vector();
    
        void PushBack(const T &data);
    
        void PopBack();
        // ...
    
        size_t Size() { return _size; }
    
        T &operator[](size_t pos) {
            assert(pos < _size);
            return _pData[pos];
        }
    
    private:
        T *_pData;
        size_t _size;
        size_t _capacity;
    };
    
    // 注意:类模板中函数放在类外进行定义时,需要加模板参数列表
    template<class T>
    Vector<T>::~Vector() {
        if (_pData)
            delete[] _pData;
        _size = _capacity = 0;
    }
    
    class Date {
    public:
        Date() : _year(1), _month(1), _day(1) {
        }
    
    private:
        int _year;
        int _month;
        int _day;
    };
    
  • 注意:Vector不是具体的类,是编译器根据被实例化的类型生成具体类的模具

3.3、类模板的实例化

  • 类模板实例化与函数模板实例化不同,类模板实例化需要在类模板名字后跟<>,然后将实例化的类型放在<>中即可,类模板名字不是真正的类,而实例化的结果才是真正的类

    // Vector是类名, Vector<类型>才是类型
    int main() {
        Vector<int> it;
        Vector<Date> dt;
        return 0;
    }
    

OKOK,C++模版就到这里。如果你对Linux和C++也感兴趣的话,可以看看我的主页哦。下面是我的github主页,里面记录了我的学习代码和leetcode的一些题的题解,有兴趣的可以看看。

Xpccccc的github主页

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/210076.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

html个人简历网页版源码

文章目录 1.个人简历1.1 简历风格1 - 纯净版1.2 简历风格2 - 蓝色版1.2 简历风格3 - 粉色心动版 源码目录结构源码下载 作者&#xff1a;xcLeigh 文章地址&#xff1a;https://blog.csdn.net/weixin_43151418/article/details/134752070 html个人简历网页版源码&#xff0c;好看…

SpringBoot整合JavaMail

SpringBoot整合JavaMail发一个简单邮件 文章目录 SpringBoot整合JavaMail发一个简单邮件导入坐标配置写客户端 SpringBoot整合JavaMail发多部件邮件 导入坐标 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starte…

SEO插件,免费的SEO插件大全

SEO插件的作用 让我们来谈谈SEO插件的作用。SEO插件是一种能够在网站建设和管理过程中&#xff0c;提供全方位、智能化SEO服务的工具。它们通常嵌入在网站后台&#xff0c;为站长提供了诸如关键词优化、页面结构调整、外链管理等一系列强大功能&#xff0c;帮助站长更好地适应…

【数电笔记】最小项(逻辑函数的表示方法及其转换)

目录 说明&#xff1a; 逻辑函数的建立 1. 分析逻辑问题&#xff0c;建立逻辑函数的真值表 2. 根据真值表写出逻辑式 3. 画逻辑图 逻辑函数的表示 1. 逻辑表达式的常见表示形式与转换 2. 逻辑函数的标准表达式 &#xff08;1&#xff09;最小项的定义 &#xff08;2&am…

一篇短文让你彻底理解什么是逻辑门电路

一、门电路概述 门电路&#xff1a;实现基本运算、复合运算的单元电路&#xff0c;如与门、与非门、或门… 注意&#xff1a;门电路中以高/低电平表示逻辑状态的1/0 正逻辑与负逻辑&#xff1a; 正逻辑&#xff1a;高电平表示1、低电平表示0 负逻辑&#xff1a;高电平表示0、低…

2022-06-17 github 访问慢的解决办法 - 手动添加hosts

访问https://hosts.gitcdn.top/hosts.txt 将网页的全部内容粘贴到你电脑的hosts文件中 在系统中找到 hosts 文件 Window&#xff1a;C:\Windows\System32\drivers\etc\hosts 或 Linux&#xff1a;/etc/hosts

Hdoop学习笔记(HDP)-Part.12 安装HDFS

目录 Part.01 关于HDP Part.02 核心组件原理 Part.03 资源规划 Part.04 基础环境配置 Part.05 Yum源配置 Part.06 安装OracleJDK Part.07 安装MySQL Part.08 部署Ambari集群 Part.09 安装OpenLDAP Part.10 创建集群 Part.11 安装Kerberos Part.12 安装HDFS Part.13 安装Ranger …

Embedding And Word2vec

Embedding与向量数据库&#xff1a; Embedding 简单地说就是 N 维数字向量&#xff0c;可以代表任何东西&#xff0c;包括文本、音乐、视频等等。要创建一个Embedding有很多方法&#xff0c;可以使用Word2vec&#xff0c;也可以使用OpenAI 的 Ada。创建好的Embedding&#xff…

IDEA下载和安装

IDEA的下载和安装 一、概述 IDEA全称IntelliJ IDEA&#xff0c;是用于Java语言开发的集成环境&#xff0c;它是业界公认的目前用于Java程序开发最好的工具。 集成环境&#xff1a;把代码编写&#xff0c;编译&#xff0c;执行&#xff0c;调试等多种功能综合到一起的开发工具…

论文阅读 - LoRA: Low-Rank Adapatation of Large Language Models

论文链接 arxiv&#xff1a; 论文目标与背景 大语言模型有很好的性能&#xff0c;在对接下游任务&#xff08;DownStream&#xff09;完成大语言模型的微调 主要方法 &#xff1a;冻结预训练模型的权重&#xff0c;插入可训练的秩分解矩阵到Transformer结构的每一层&#…

Facebook做外贸推广如何?

Facebook作为全球最大的社交媒体平台之一&#xff0c;同时也拥有着庞大的流量以及用户&#xff0c;基于这些数据更是吸引着不少的跨境电商卖家选择此平台进行推广营销&#xff0c;那么Facebook做外贸推广到底如何呢&#xff1f;下面小编对此讲讲吧&#xff01; 1、全球覆盖流量…

Spring Boot统一异常处理 Spring拦截器

小编在前文中向大家描述了Spring AOP的相关内容&#xff1a;Spring AOP-CSDN博客感兴趣的各位老铁可查看一下&#xff01;&#xff01; 那么&#xff0c;我们本文主要是代理搭建来实现一个Spring Boot统一功能处理模块了&#xff0c;当然&#xff0c;这个也是Spring AOP的实战环…

SQL Server 2016(为数据表Porducts添加数据)

1、实验环境。 某公司有一台已经安装了SQL Server 2016的服务器&#xff0c;并已经创建了数据库PM。 2、需求描述。 在数据库PM中创建表products&#xff0c;"编号"列的值自动增长并为主键。然后使用T-SQL语句为表格插入如下数据。 3、实验步骤。 1、使用SSMS管理工…

第九节HarmonyOS 常用基础组件1-Text

一、组件介绍 组件&#xff08;Component&#xff09;是界面搭建与显示的最小单位&#xff0c;HarmonyOS ArkUI声名式为开发者提供了丰富多样的UI组件&#xff0c;我们可以使用这些组件轻松的编写出更加丰富、漂亮的界面。 组件根据功能可以分为以下五大类&#xff1a;基础组件…

如何优雅的进行业务分层

1.什么是应用分层 说起应用分层&#xff0c;大部分人都会认为这个不是很简单嘛 就controller&#xff0c;service, mapper三层。 看起来简单&#xff0c;很多人其实并没有把他们职责划分开&#xff0c;在很多代码中&#xff0c;controller做的逻辑比service还多,service往往当…

C/C++,图算法——求强联通的Tarjan算法之源程序

1 文本格式 #include <bits/stdc.h> using namespace std; const int maxn 1e4 5; const int maxk 5005; int n, k; int id[maxn][5]; char s[maxn][5][5], ans[maxk]; bool vis[maxn]; struct Edge { int v, nxt; } e[maxn * 100]; int head[maxn], tot 1; vo…

BUUCTF-MISC-第二题

下载并打开题目附件 图片是GIF格式动态图片 动态过程会时不时弹出flag 但是速度很快 我们需要想办法去拦截 使用Stegsolve工具进一步分析Analyse->Frame Browser 对图片进行锁帧操作 21帧51帧79帧得到flag&#xff1a;flag{he11ohongke} 本题意义&#xff1a; 对MISC图片隐写…

CSS 绝对定位问题和粘性定位介绍

目录 1&#xff0c;绝对定位问题1&#xff0c;绝对定位元素的特性2&#xff0c;初始包含块问题 2&#xff0c;粘性定位注意点&#xff1a; 1&#xff0c;绝对定位问题 1&#xff0c;绝对定位元素的特性 display 默认为 block。所以行内元素设置绝对定位后可直接设置宽高。脱离…

JS 实现一键复制文本内容

1、演示&#xff1a; 2、代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>一键复制</title&g…

树莓派搭建开发环境

背景 自从上次心血来潮给树莓派装完系统&#xff0c;一直没想好怎么具体使用它的场景&#xff0c;它就这样默默地躺在抽屉吃灰了一年 再次想起它&#xff0c;是一个周日的下午&#xff1a;收到之前在腾讯云买的云服务器快过期的提醒&#xff0c;一个4核8G内存的ubuntu&#x…