【C++】提高 -- 函数模板

提高阶段针对C++泛型编程和STL技术探讨深层次使用

目录

一、模板概念

二、函数特点

三、函数模板

四、普通函数和函数模板的区别

五、普通函数和模板函数的调用规则

六、模板的局限性


一、模板概念

        建立通用的模具,提高复用性;C++的另一种编程思想称为泛型编程,主要利用的技术是模板

        学习模板可以更好的运用后续STL系统提供的模板

二、函数特点

        ①不可以直接使用

        ②模板的通用不是万能的

三、函数模板

不具体指定函数返回值和形参的类型,用虚拟的类型代表:T function(T a)

目的:提高代码复用性,将类型参数化

语法:

template<typename T>
//函数声明或定义

template -- 声明创建模板

typename -- 表明后面的符号是一个数据类型,可以用class代替

T -- 通用数据类型,名称可以用其他大写字母代替

案例引入:

//交换两个整型的函数
void swapInt(int &a, int &b)
{
    int temp = a;
    a = b;
    b = temp;
}

//交换两个浮点型的函数
void swapDouble(double &a, double &b)
{
    double temp = a;
    a = b;
    b = temp;
}

观察以上两个函数的不同之处仅为形参的类型,故可以利用一个函数可传入多种数据类型简化代码

template<typename T> //声明一个模板告诉编译器后面代码中紧跟的T不要报错,T是通用数据类型,在使用时才会被指定
void Swap(T &a, T &b)
{
    T temp = a;
    a = b;
    b = temp;
}

//使用模板函数

//方法1:自动类型推导
int a = 10;
int b = 20;
Swap(a,b);

//方法2:显示指定类型,函数后跟着的<>内容是指定上述模板函数的T类型
Swap<int>(a,b);

注意事项:

        ①使用自动类型推导时,必须推导出一致的数据类型T才可以使用(形参的数据类型一致)

        ②模板必须要确定出T的数据类型才能使用(如果该模板函数形参是空白,需要用显示指定类型随便写一个类型)

案例实操-对不同数据类型的数组进行选择排序(从大到小),测试组 int 和 char 类型:

template<typename T>
void Swap(T &a, T &b)
{
    T temp = a;
    a = b;
    b = temp;
}

template<class T>
void change(T &a[],int len)
{
    for(int i = 0; i<len; i++)
    {
        int max = i;
        for(int j=i+1; j<len; j++)
        {
            if (a[max]<a[j+1])
            {
                max = j;
            }
        }
        if(max != i)
        {
            swap(a[max],a[i]);
        }
    }
}

template<typename T>
void printArr(T arr[],int len)
{
    for(int i=0; i<len; i++)
    {
        cout << arr[i] << " ";
    }
    cout << endl;
}

void test01()
{
    char charArr[] = "badcfe";
    int num = sizeof(charArr) / sizeof(char);
    change(charArr,num);
    printArr(charArr,num)
}

void test02()
{
    int intArr[] = {7,5,1,3,9,2,4,6,8};
    int num = sizeof(intArr) / sizeof(int);
    change(intArr,num);
    printArr(intArr,num)
}
四、普通函数和函数模板的区别

普通函数在使用时可以发生自动类型转换 [隐式类型转换:将double类型赋给int]

int add(int a, int b)
{
    return a+b;
}

void test01()
{
    int a = 10;
    int b = 20;
    char c = 'c';
    //可以运行
    add(a,b);
    //可以运行,将字符变量转化为ascii的值99赋值给int类型
    add(a,c);
}

函数模板使用时,如果利用自动类型推导不会发生隐式类型转换;如果利用显示执行类型可以发生隐式类型转换

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

void test()
{
    int a = 10;
    int b = 20;
    char c = 'c';
    //可以运行
    add(a,b);
    //自动类型推导不可以运行,无法推导出T的类型
    add(a,c);
    //显示指定类型可以运行
    add<int>(a,c);
    
}

利用模板函数时,建议使用显示指定类型方式调用模板函数,因为自己可以确定T类型

五、普通函数和模板函数的调用规则

①如果函数模板和普通函数都可以实现,优先调用普通函数

②可以通过空模板参数列表强制调用模板函数:print<>(a,b);

③函数模板可以发生重载

④如果函数目标你可以产生更好的匹配,优先调用函数模板

如果有模板函数,就尽量不要再写重名的普通函数,避免出现二义性

六、模板的局限性

模板的通用性不是万能的

template<typename T>
void f(T a, T b)
{
    a = b;
}

以上模板如果a和b是一个数组的话,赋值操作就无法实现

template<typename T>
void f(T a, T b)
{
    if(a > b){....}
}

以上模板如果自定义类型T是Person类的自定义数据类型,则无法正常运行

为解决以上问题,C++提供模板的重载

class Person
{
public:

    Person(string name, int age)
    {
        this.m_Name = name;
        this.m_Age = age;
    }

    string m_Name; 
    int m_Age;
};

template<typename T> 
bool Com(T &a, T &b)
{
    if(a == b)
    {
        return true;
    }
    else
    {
        return false;
    }
}

template<> bool Com(Person &p1, Person &p2)
{
    if(p1.m_Name == p2.m_Name && p1.m_Age == p2.m_Age)
    {
        return true;
    }
    else
    {
        return false;
    }
}

void test()
{
    Person p1("TOM",10);
    Person p2("TOM",10);

    bool ret = Com(p1,p2);
    if(ret)
    {
        cout << "p1 == p2" << endl;
    }
    else
    {
        cout << "p1 != p2" << endl;
    }   

}

注意:template<>是显示具体化的原型,即通过名称指出类型,优先于常规模板

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值