• C++--第20课


    第20课 - 函数模板

    1. C++中如何交换两个变量的值?

    void Swap(int& a, int& b)

    {

    int t = a;

    a = b;

    b = t;

    }

    void Swap(float& a, float& b)

    {

    float t = a;

    a = b;

    b = t;

    }

    void Swap(char *& a, char *& b)

    {

    char *& t = a;

    a = b;

    b = t;

    }

    除了类型不同,函数体代码完全相同。C++强调代码复用,那如何来解决代码冗余的问题呢?

    2. 泛型编程

    不考虑具体类型的编程模式。我们先考虑算法,再考虑类型。

    对于Swap函数可以考虑下面的泛型写法

    void Swap(T& a, T& b)

    {

    T t = a;

    a = b;

    b = t;

    }

    Swap泛型写法中的T不是一个具体的数据类型,而是泛指任意的数据类型。

    (1)函数模板

    提供了一种特殊的函数可用不同类型进行调用,看起来和普通的函数很相似,区别是类型可被参数化。

    template <typename T>

    void Swap(T& a, T& b)

    {

    T t = a;

    a = b;

    b = t;}

    (2)函数模板的语法规则

    template关键字用于声明开始进行泛型编程。

    typename关键字用于声明泛指类型。

    (3)函数模板的应用

    自动类型推导调用

    具体类型显示调用

    #include <cstdlib>

    #include <iostream>

    using namespace std;

    template<typename T>

    void Swap(T& a, T& b)

    {

        T t = a;

        a = b;

        b = t;

    }

    int main(int argc, char *argv[])

    {

        int a = 1;

        int b = 2;

        Swap(a, b); //自动类型推导:a和b均是int,因此类型参数T为int

        cout<<"a = "<<a<<endl;

        cout<<"b = "<<b<<endl; 

        float fa = 3;

        float fb = 4; 

        Swap<float>(fa, fb);  //显示类型调用:用loat替换参数类型T 

        cout<<"fa = "<<fa<<endl;

        cout<<"fb = "<<fb<<endl;

        char ca = 'a';

        char cb = 'b';

        Swap(ca, cb);

        cout<<"ca = "<<ca<<endl;

        cout<<"cb = "<<cb<<endl;

        cout << "Press the enter key to continue ...";

        cin.get();

        return EXIT_SUCCESS;

    }

    运行结果:

    a = 2

    b = 1

    fa = 4

    fb = 3

    ca = b

    cb = a

    3. 泛型编程初体验(排序算法)

    #include <cstdlib>

    #include <iostream>

    using namespace std;

    template<typename T>

    void Swap(T& a, T& b)

    {

        T t = a;

        a = b;

        b = t;

    }

    template<typename T>

    void SelectSort(T array[], int length)//选择排序

    {

             for(int i = 0; i<length; i++) //全循环

             {

                      T min = array[i];

                      int index = i;

                      for(int j = i+1; j < length; j++)

                      {

                               if( array[j] < min)  //找最小

                               {

                                        min = array[j];

                                        index = j; 

                               }       

                      }

                      Swap(array[i],array[index]);             

             }

    }

    int main(int argc, char *argv[])

    {

        int array[] = {3, 2, 5, 3 , 4};

        SelectSort<int>(array, 5);

        for(int i=0; i<5; i++)

        {

            cout<<array[i]<<endl;

        }

        char ca[] = {'b', 'c', 'a', 'e', 'd', 'f'};

        SelectSort(ca, 6);

        for(int i=0; i<6; i++)

        {

            cout<<ca[i]<<endl;

        }

        cout << "Press the enter key to continue ...";

        cin.get();

        return EXIT_SUCCESS;

    }

    运行结果:

    2

    3

    3

    4

    5

    a

    b

    c

    d

    e

    f

    l  函数模板的深入理解:

    编译器并不是把函数模板处理成为能够处理任意类型的函数。

    编译器从函数模板通过具体类型产生不同的函数。(用几个类型产生几个函数)

    编译器会对函数模板进行两次编译:在声明的地方对模板代码本身进行编译,在调用的地方对参数替换后的代码进行编译。

    问:

    当函数模板遇到函数重载会发生什么?

    4. 函数模板与函数重载

    函数模板可以像普通函数一样被重载。C++编译器优先考虑普通函数,如果函数模板可以产生一个更好的匹配,那么选择模板。可以通过空模板实参列表的语法限定编译器只通过模板匹配。

    #include <cstdlib>

    #include <iostream>

    using namespace std;

    int Max(int a, int b) //与函数模板重名,这两者重载。 这两个函数不会发生冲突。

    {

        cout<<"int Max(int a, int b)"<<endl;

        return a > b ? a : b;

    }

    template<typename T> //优先考虑普通函数。

    T Max(T a, T b)

    {

        cout<<"T Max(T a, T b)"<<endl;

        return a > b ? a : b;

    }

    template<typename T>

    T Max(T a, T b, T c)

    {

        cout<<"T Max(T a, T b, T c)"<<endl;

        return Max(Max(a, b), c);

    }

    int main(int argc, char *argv[])

    {

        int a = 1;

        int b = 2;

        cout<<Max(a, b)<<endl;

        cout<<Max<>(a, b)<<endl;

        cout<<Max(3.0, 4.0)<<endl;

        cout<<Max(5.0, 6.0, 7.0)<<endl;

        cout<<Max('a', 100)<<endl; //不允许自动类型转换,只能调用普通函数。

        cout << "Press the enter key to continue ...";

        cin.get();

        return EXIT_SUCCESS;

    }

    运行结果:

    int Max(int a, int b)

    2

    T Max(int a, int b)

    2

    T Max(int a, int b)

    4

    T Max(T a, T b, T c)

    T Max(int a, int b)

    T Max(int a, int b)

    7

    int Max(int a, int b)

    100

    注意事项:

    函数模板不允许自动类型转化,普通函数能够进行自动类型转换。

    cout<<Max(‘a’, 100)<<endl; 必然只会调用普通函数。

    5. 多参数函数模板

    函数模板可以定义任意多个不同的类型参数

    template<typename T1, typename T2, typename RT>

    RT Add(T1 a, T2 b)

    {

    return static_cast<RT>(a + b)

    }

    cout<<Add<char, float, double >(‘a’, 100)<<endl;

    问题:

    多类型参数的模板可以进行自动类型推导吗?

    当生命的类型参数为返回值类型时,无法进行自动类型推导。

    #include <cstdlib>

    #include <iostream>

    using namespace std;

    template<typename RT, typename T1, typename T2>

    RT Add(T1 a, T2 b)

    {

        return static_cast<RT>(a + b);

    }

    int main(int argc, char *argv[])

    {

        cout<<Add<double, char, float>('a', 100.0f)<<endl;

        cout<<Add<double>('a', 100.0f)<<endl;   //只定义返回值类型

        //cout<<Add('a', 100.0f)<<endl;  这样写会报错

        cout << "Press the enter key to continue ...";

        cin.get();

        return EXIT_SUCCESS;

    }运行结果:

    197

    197

    l  不完美的解决方案

    将返回值类型参数声明到第一个参数的位置,调用时只需显示声明反水类型参数即可。

    小结:

    函数模板起始是一个具有相同行为的函数家族。

    函数模板可以根据类型实参对函数进行推导调用。

    函数模板可以显示指定的类型参数。

    函数模板可以被重载。

  • 相关阅读:
    地图篇-02.地理编码
    地图篇-01.获取用户位置
    新手教程之使用Xib自定义UITableViewCell
    封装
    NSDate简单介绍
    OC知识点归纳
    Xcode的控制台调试命令
    [开发笔记]UIApplication介绍
    技术分享-开发利器block底层实现
    技术分享-开发利器block
  • 原文地址:https://www.cnblogs.com/free-1122/p/11336241.html
Copyright © 2020-2023  润新知