• C++初阶(十)模板初阶


    在这里插入图片描述


    📘北尘_个人主页

    🌎个人专栏:《Linux操作系统》《经典算法试题 》《C++》 《数据结构与算法》

    ☀️走在路上,不忘来时的初心


    一、泛型编程

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

    在这里插入图片描述
    使用函数重载虽然可以实现,但是有一下几个不好的地方:

    1. 重载的函数仅仅是类型不同,代码复用率比较低,只要有新类型出现时,就需要用户自己增加对应的函
    2. 代码的可维护性比较低,一个出错可能所有的重载均出错

    2、引出模板

    那能否告诉编译器一个模子,让编译器根据不同的类型利用该模子来生成代码呢?
    在这里插入图片描述
    如果在C++中,也能够存在这样一个模具,通过给这个模具中填充不同材料(类型),来获得不同材料的铸件(即生成具体类型的代码),那将会节省许多头发。巧的是前人早已将树栽好,我们只需在此乘凉。
    泛型编程:编写与类型无关的通用代码,是代码复用的一种手段。模板是泛型编程的基础。
    在这里插入图片描述


    二、函数模板

    1、函数模板概念

    函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型版本。

    2、函数模板格式

    template
    返回值类型 函数名(参数列表){}
    在这里插入图片描述
    注意:typename是用来定义模板参数关键字,也可以使用class(切记:不能使用struct代替class)

    3、函数模板的原理

    那么如何解决上面的问题呢?大家都知道,瓦特改良蒸汽机,人类开始了工业革命,解放了生产力。机器生产淘汰掉了很多手工产品。本质是什么,重复的工作交给了机器去完成。有人给出了论调:懒人创造世界。
    在这里插入图片描述
    在这里插入图片描述

    函数模板是一个蓝图,它本身并不是函数,是编译器用使用方式产生特定具体类型函数的模具。所以其实模板就是将本来应该我们做的重复的事情交给了编译器
    在这里插入图片描述
    在编译器编译阶段,对于模板函数的使用,编译器需要根据传入的实参类型来推演生成对应类型的函数以供调用。比如:当用double类型使用函数模板时,编译器通过对实参类型的推演,将T确定为double类型,然后产生一份专门处理double类型的代码,对于字符类型也是如此。

    对于上述代码,我们可以验证他们调用的不是同一个函数,由此可以更好的理解模板

    在这里插入图片描述

    4、函数模板的实例化

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

    1、隐式实例化

    在这里插入图片描述
    在这里插入图片描述

    2、显式实例化

    在这里插入图片描述
    如果类型不匹配,编译器会尝试进行隐式类型转换,如果无法转换成功编译器将会报错。

    5、 模板参数的匹配原则

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

    在这里插入图片描述

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

    在这里插入图片描述

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


    三、类模板

    1、类模板的定义格式

    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    2、类模板的实例化

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

    // Vector类名,Vector才是类型
    Vector<int> s1;
    Vector<double> s2;
    
    • 1
    • 2
    • 3

  • 相关阅读:
    C++类大小计算
    vsc连接wsl安装vsc时遇到权限问题的解决方案
    Vue 导出前端数据报表为xlsx文件
    使用 AI 学习 Python web 的 django 代码(1/30天)
    从某达OA到Yii2框架的cookie反序列化漏洞研究
    cube-studio配置镜像仓库并允许
    基于SpringBoot+Vue+uniapp的高校疫情管理系统(源码+lw+部署文档+讲解等)
    附录A 程序员工作面试的秘密
    精品springboot的二手车管理系统vue
    用Python构建区块链
  • 原文地址:https://blog.csdn.net/2301_78995005/article/details/134338440