C++模版

这篇具有很好参考价值的文章主要介绍了C++模版。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


C++模版,C/C++,c++,java,数据结构

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、函数模版原理

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

    C++模版,C/C++,c++,java,数据结构

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

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

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

      C++模版,C/C++,c++,java,数据结构

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;
    }
    

    C++模版,C/C++,c++,java,数据结构

  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;
    }
    

    C++模版,C/C++,c++,java,数据结构

  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主页文章来源地址https://www.toymoban.com/news/detail-757071.html

到了这里,关于C++模版的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 数据结构——栈(C++实现)

    今天我们来看一个新的数据结构—— 栈 。 栈是一种基础且重要的数据结构,它在计算机科学和编程中扮演着核心角色。栈的名称源于现实生活中的概念,如一叠书或一摞盘子,新添加的物品总是放在顶部,而取出物品时也总是从顶部开始。这种后进先出(Last In, First Out, L

    2024年04月29日
    浏览(42)
  • 数据结构——队列(C++实现)

    目录 队列的概念及结构  队列的实现 队列的代码实现 完整的源文件代码 总结 推荐题目巩固知识 队列:只允许在一端进行插入数据操作,在另一端进行删除操作的特殊线性表,队列最重要的特性是 先进先出 (First In First Out) 入队列:进行插入操作的一端称为 队尾 出队列

    2024年02月07日
    浏览(42)
  • c++【数据结构】 八大排序

    在计算机科学中,排序算法是最重要的算法之一。排序算法可以将一组无序的数据按照一定的规则重新排列,使其变为有序的数据集合。排序算法的应用十分广泛,它们在计算机科学、数据结构、数据库、人工智能、机器学习等领域都扮演着重要的角色。 本文将介绍C++/C语言

    2024年02月10日
    浏览(49)
  • C++数据结构学习——栈

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 栈(Stack)是计算机科学中一种常见的数据结构,它是一种线性数据结构,具有特定的添加和删除元素的方式,遵循\\\"先进后出\\\"(Last In, First Out,LIFO)原则。栈通常用于管理函数调用、表达式求值、内存

    2024年02月11日
    浏览(35)
  • C++数据结构--红黑树

    红黑树,是一种二叉搜索树,但在每个结点上增加一个存储位表示结点的颜色,可以是Red或Black。 通过对任何一条从根到叶子的路径上各个结点着色方式的限制,红黑树确保没有一条路 径会比其他路径长出俩倍,因而是接近平衡的。如图所示: 每个结点不是红色就是黑色。

    2024年02月09日
    浏览(49)
  • 数据结构-B树的特点结构与C++实现

    目录 1. 引言 2. 什么是B树 3. B树的特点 3.1 平衡性 3.2 多路搜索树 3.3 高度平衡 4. B树的应用场景 4.1 文件系统 4.2 数据库系统 4.3 索引结构 5. B树的基本操作 5.1 插入操作 5.2 删除操作 5.3 查找操作 6. B树与其他数据结构的比较 6.1 B树与二叉搜索树 6.2 B树与红黑树 7. C++代码实现 8.

    2024年02月09日
    浏览(44)
  • 【数据结构】红黑树(C++实现)

    👀 樊梓慕: 个人主页  🎥 个人专栏: 《C语言》 《数据结构》 《蓝桥杯试题》 《LeetCode刷题笔记》 《实训项目》 《C++》 《Linux》 《算法》 🌝 每一个不曾起舞的日子,都是对生命的辜负 目录 前言 1.概念 2.性质 3.节点的定义  4.插入 4.1情况1:叔叔u存在且为红 4.2情况2:

    2024年03月13日
    浏览(54)
  • C++数据结构之vector

    vector数组是一个能存放任意数据类型(类,结构体,普通变量类型等)的动态数组,在数据结构中就相当于顺序储存的线性表,寻找元素非常快,但是插入元素的时间却很大(list是一个双向链表,在同一个位置插入大量的数据时速度很快,但是查找的速度就会慢很多) 和普

    2024年02月04日
    浏览(50)
  • 数据结构——优先队列c++详解

    百度百科定义 优先队列是0个或多个元素的集合,每个元素都有一个优先权或值,对优先队列执行的操作有1) 查找;2) 插入一个新元素;3) 删除.在最小优先队列(min priority queue)中,查找操作用来搜索优先权最小的元素,删除操作用来删除该元素;对于最大优先队列(max priority queue),查找操

    2024年02月09日
    浏览(41)
  • C++ 高级数据结构————[ 单调栈 ]

    每周一篇的算法文章来了 今天讲解的是高级数据结构中的——单调栈 单调栈,顾名思义,就是升级版的栈() 先回顾一下栈把 栈 ,是一种线性表,它的特点是只能从一边进出,并且先进后出,后进先出。就想枪的弹夹一样。 而单调栈,跟他有一点不同 单调栈 ,每时每刻

    2023年04月20日
    浏览(35)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包