• 浅述C++模板——函数模板及类模板


    前言

    模板作为 C++ 的一大特色,对于泛型编程有着重要的作用。同时,对于大规模类似的函数或是类型不确定的类,模板都起了至关重要的作用。

    一、模板

    在开始学习模板之前,我们首先需要了解模板。先看下面一个例子:

    #include 
    using namespace std;
    
    int func_one(int num){
        return 2 * num;
    }
    
    double func_two(double num){
        return 2 * num;
    }
    
    int main(){
        int num_int = 2;
        double num_double = 2;
        
        func_one(num_int);
        func_two(num_doule);
        
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    我们可以轻易发现,对于函数 func_one、func_two,两者实现的功能基本相同,只是所接受的参数和返回值发生了对应的变化。因此有没有一种办法可以简化这两个函数,将其合并为一个呢?答案就是使用模板。

    下面的例子是对上面的两个函数使用模板的结果:

    #include 
    using namespace std;
    
    template 
    T func(T num){
        return 2 * num;
    }
    
    int main(){
        int num_int = 2;
        double num_double = 2;
        
        func(num_int);
        func(num_doule);
        
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    在上面的案例中我们见到了新的关键字 template。它表示此处运用模板,后面 <> 中则表示,有一个模板类型 T,T 在此会根据我们函数的传参自动生成对应的类型。例如 num_int 传入后 T 则代表 int; num_double 传入后 T 则代表 double。

    模板就像一个空的模具,大体上不会改变,但是你提供什么参数都可以按照模具的形状进行操作

    二、函数模板

    在上面介绍时我们使用的模板就是函数模板,除此之外还有类模板,但是我们先从函数模板开始讲起。

    2.1 模板的格式

    **函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型版本。**函数模板的诞生是为了简化重复的函数,哪怕利用重载,也需要对一个函数进行多次重载,但是模板函数只需一个模板即可适应各个种类。

    函数模板的格式如下:

    template

    返回值类型 函数名(参数列表){

    ​ 函数主体;

    }

    声明一个模板类型的时候,可以使用 “class” 或 “typename”,两者无差别。但是需要注意的地方在于,一个模板类型只能代表一种类型。例如在上面的函数中,T1 实例化为 int 类型后就不能再代表 char 等类型,具体如下:

    #include 
    using namespace std;
    
    template 
    double func_one(T1 num_1, T1 num_2){
        return num_1 + num_2;
    }
    
    template 
    double func_two(T1 num_1, T2 num_2){
        return num_1 + num_2;
    }
    
    int main(){
        int num_int = 2;
        double num_double = 2;
        
        func_one(num_int, num_double);
        func_two(num_doule, num_double);
        
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    在这个例子中,主函数中调用 func_one 是失败的,T1 在接收 num_1 时,已经实例化为 int, 但是 num_2 为 double 类型,因此发生了错误。为接收不同类型的两个参数,我们可以考虑使用 func_two。

    2.2 模板的匹配优先度

    先看下面的案例,猜测系统会调用哪个函数。

    #include 
    using namespace std;
    
    int func(int num_1, int num_2){
        return num_1 + num_2;
    }
    
    template 
    int func(T1 num_1, T1 num_2){
        return num_1 + num_2;
    }
    
    int main(){
        int num_1 = 1;
        int num_2 = 2;
        
        func(num_1, num_2);
        func(num_1, num_2);
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    经过调试,我们可以得知:

    第一次调用 func 函数,调用的是第一个非模板的 func 函数,这是由于在可以找到匹配的函数时,优先不调用模板函数,避免重复生成一个一样的函数;

    第二次调用 func 函数,调用的模板生成函数,这是由于 func(), 表示我们手动要求生成一个 func 模板函数用 int 实例化之后的函数,此时会优先采用手动要求的模板函数。

    2.3 模板的声明

    比起其他的函数,模板函数要求必须声明和定义在一起,不可声明与定义分离。此过程涉及到编译链接的过程,不在此展开。

    三、类模板

    在了解了函数模板之后,类模板也非常好理解,例如我们之后会学到的 vector 容器就是一个模板类:

    #include 
    using namespace std;
    
    template 
    class vector{
    private:
        T* ptr;
    public:
        vector(T num){
            // ......
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    在这个类中,构造一个类时需要传入一个类型作为参数,然后 ptr 的类型就确定了,之后的函数就可以据此继续完成。之后将以 vector 为例,讲述一个模板类的实现。

    四、总结

    模板的优点显而易见,一方面节省了资源,便于代码的迭代更新,另一方面增加了代码的灵活性。那是不是我们要多多使用模板呢?答案是否定的。

    首先模板相比于普通的函数需要的编译时间更长,且出现错误信息时不易定位错误位置。所以具体使用重载还是模板要根据实际情况来合理进行判断选取。

  • 相关阅读:
    内核中的互斥锁的使用
    面试买书复习就能进大厂?
    十大排序算法之——冒泡排序算法(Java实现)及思路讲解
    第六章 图 二、图的存储结构(邻接矩阵法)
    (转)冒泡排序及优化详解
    剑指offerDayN之请教大佬
    java计算机毕业设计在线影院系统源码+系统+mysql数据库+lw文档+部署
    idea所有历史版本下载
    React + 项目(从基础到实战) -- 第九期
    c++ Strategy模式
  • 原文地址:https://blog.csdn.net/qq_62306969/article/details/132736277