函数模板 与 类模板 详解 (超详细) 文章附代码

        在C++编程的世界里,为了提高代码的复用率,提高程序员的开发效率,C++引入了函数模板类模板这种泛型编程;即在定义函数和类的时候,用一个标志来表示参数的类型,不是实际的类型。这种方法是一种能使代码不再局限于任何特定类型的编程。本文章详细描述如何使用函数模板与类模板。 注:笔者入行时间不太长,以下内容大多为学习过程中的心得体会与总结分享给大家,本此也是第一次发文章,如有错误欢迎大家批评指正!感谢!

目录

一. 函数模板

1.1 定义一个函数模板

1.2 函数模板的调用方法

1.3 普通函数和函数模板的比较

1.4 函数模板重载

1.5 函数模板特化

1.6 多文件函数模板

1.7 函数模板的嵌套

1.8 函数模板的非类型参数

一. 函数模板

1.1 定义一个函数模板

 定义格式:template <class T1,typename T2>
                   函数返回值类型  函数名 (参数) {  }

template <class T1, typename T2>
int fun(T1 a, T2 b)
{
}

上述代码解释:

        template:关键字,声明创建模板。
        typename/class:二者作用相同,表明后面修饰的类型是一个通用类型,或叫做虚拟类型。
        T1/T2:通用类型或者虚拟类型名,可以在函数中直接当做普通类型使用,用于修饰变量。

1.2 函数模板的调用方法

函数模板有如下两种调用方法:
第一种:函数名 <实际类型> (参数);
              显式类型推导   fun <int> (1, 2);
第二种:函数名(参数);
              隐形类型推导   fun (2.2, 1.5);

#include <iostream>
using namespace std;

template <typename T>
void add_fun(T a, T b) //函数模板
{
    cout << "a + b = " << a + b << endl;
}

int main(int argc, char const *argv[])
{
    add_fun<int>(10, 2); //显示类型推导
    add_fun(12.1, 9.8);  //隐式类型推导
    return 0;
}

注意:显示类型推导参数和推导的类型必须一致

1.3 普通函数和函数模板的比较

        1.普通函数只可以有一种数据类型相匹配。而模板函数可以有多种类型。
        2.隐式推导优先使用普通函数,只有当普通函数不匹配的时候才使用函数模板。
        3.函数模板只有在调用时,才会构建函数,而普通函数在编译时构建函数。
        4.普通函数调用时候可以发生自动类型转换,而函数模板不行

1.4 函数模板重载

        函数模板的重载和普通函数的重载相似。也是同一个作用域类函数名相同参数列表不同,主要为两种类型的重载
1,参数顺序不同的重载:
        template <class T1,class T2>        void fun(T2 a,T1 b)
        template <class T1,class T2>        void fun(T1 a,T2 b)
注意:在函数参数顺序不同的重载中,模板实例化的时候不可以是相同类型。                                           例如:fun<int , int > (1,2),这中情况下编译器无法识别应该匹配哪个重载版本的函数,造成冲突
2,参数个数不同的重载
        template <class T1,class T2>    void fun(T1 a,T2 b)
        template <class T1>                  void fun(T1 a)
这种情况下的重载,给函数传入不同个数的参数,则调用不同版本的重载。

1.5 函数模板特化

        作用:为了解决函数模板的部分局限性,在定义函数模板时候,直接确定好T的类型。也就是特定的类型模板。
        格式: template<class T> 返回值                                                                                                                  函数名(参数类型 参数) { }

#include <iostream>
using namespace std;

template <typename T>
void add_fun(T a, T b) //函数模板
{
    cout << "a + b = " << a + b << endl;
    cout << "我是函数模板" << endl;
}

template <typename T>
void add_fun(double a, double b) //函数模板
{
    cout << "a + b = " << a + b << endl;
    cout << "我是特化函数模板" << endl;
}

int main(int argc, char const *argv[])
{
    add_fun<int>(12, 9); 
    add_fun<double>(12.1, 9.8); 
    return 0;
}

注意:如果特化后,类型确定才可以使用自定义类型中的成员变量和方法。

1.6 多文件函数模板

        通常情况下在定义函数或者类的时候,会用.h和cpp文件将定义和申明分开写。而用多文件实现函数模板的情况下则会出现错误。
        出现连接错误的原因:函数模板是在调用时构建的,而调用时.h文件中没有函数实现,出现连接错误,找不到函数体。
        第一种解决办法:在调用的文件中同时添加 #include <xxx.h>  和 #include <xx.cpp>
        第二种解决办法:模板的定义和声明都放在.h头文件中。

1.7 函数模板的嵌套

        通常情况下,我们可以在函数模板中还可以去调用另外一个函数模板。在下段代码中,调用add_fun三个参数的重载版本里,先调用add_fun两个参数重载版本的函数模板计算a,b两个值之和赋值给temp,通过temp再与c的值相加计算三个值的和。

#include <iostream>
using namespace std;

template <typename T>
T add_fun(T a, T b)
{
    return a + b;
}

template <typename T>
T add_fun(T a, T b, T c)
{
    T temp = add_fun<T>(a, b); //在函数模板中调用另一个重载版本的函数模板
    cout << "a + b + c = " << temp + c << endl;
    return temp + c;
}

int main(int argc, char const *argv[])
{
    add_fun<int>(12, 9, 6);
    return 0;
}

1.8 函数模板的非类型参数

        在某种特定的情况下,我们希望给函数传入一个特定的类型确定参数,但不希望通过直接传参的方式。
        这种情况下我们可以通过非类型参数实现。在模板<>中加入一个参数,但这个参数不是通用类型参数,是具体的某一个值。
        格式:template <class T , 基本数据类型 变量名>
                   返回值 函数名(T& 变量名)
        例如:template <class T,int size>
                   void showArr(T* arr); 

#include <iostream>
using namespace std;

template <typename T, int size>
void show_arr(T *a)
{
    for (int i = 0; i < size; i++)
    {
        cout << a[i] << " ";
    }
    cout << endl;
}

int main(int argc, char const *argv[])
{
    int arr[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    const int arr_size = sizeof(arr) / sizeof(arr[0]);
    show_arr<int, arr_size>(arr);
    return 0;
}

注意:上例子中,arr_size是通过模板传入到函数中,可以当普通变量使用非类型参数都是常量,在函数中不允许修改,只可以使用,所以定义非类型参数变量时候,必需要加const进行修饰

PS:为了简化文章的可读性,所以缩短篇幅内容,类模板的内容我将在下一篇文章中更新。
     

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值