zoukankan      html  css  js  c++  java
  • C++回顾day03---<模板>

    一:函数模板

    建立一个通用函数,其函数类型和形参类型不具体指定,用一个虚拟的类型来代表。这个通用函数就称为函数模板。
    凡是函数体相同的函数都可以用这个模板来代替,不必定义多个函数,只需要在模板中定义一次即可

    (一)函数模板语法

    template <类型形式参数表>
    类型 函数名(形参参数表)
    {
        执行语句;
    }
    其中类型形式参数表形式为:
    typename T1,typename T2,...,typename Tn
    或者
    class T1,class T2,...,class Tn

    (二)函数模板和普通函数相比

    (1)参数转换问题

    普通函数可以进行隐式函数类型转换
    模板函数不允许存在这种转换,类型严格一致

    (2)调用规则问题

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

    (三)函数模板的使用

    template <typename T1,typename T2>    //参数列表为2个
    void sortArray(T1* arr, T2 num)
    {
        T2 i, j;
        T1 temp;
        for (i = 0; i < num; i++)
            for (j = 0; j < num; j++)
                if (arr[i]>arr[j])
                {
                    temp = arr[i];
                    arr[i] = arr[j];
                    arr[j] = temp;
                }
    }
    
    template <typename T>
    void printArr(T* arr, int num)    //参数列表可以含有固定类型参数  返回值类型可以自定义,也可以为typename定义类型
    {
        int i;
        for (i = 0; i < num; i++)
        {
            cout << arr[i]<<" ";
        }
        cout << endl;
    }
    void main()
    {
        //测试int类型
        int a[5] = { 1, 37, 20, 19, 49 };
        sortArray(a, 5);
        printArr(a, 5);
    
        //测试float类型
        float fa[5] = { 2.6, 37.1, 62.9, 16.2, 38 };
        sortArray(fa, 5);
        printArr(fa, 5);
        
        system("pause");
    }

    (四)当函数模板遇到函数重载《重点》

    1.函数模板可以像普通函数一样被重载

    //实现参数交换
    template<typename T>
    void mySwap(T& t1, T& t2)
    {
        T temp;
        temp = t1;
        t1 = t2;
        t2 = temp;
    }
    
    void mySwap(char &b, int& a)
    {
        int temp;
        temp = a;
        a = b;
        b = temp;
    }
    
    void main()
    {
        char a = 'A';
        int b = 97;
        mySwap(a, b);
    
        cout << "a:" << a<<endl;
        cout << "b:" << b << endl;
        
        system("pause");
    }
    由于模板函数参数类型严格定义,故会去找下面的进行调用。但是不难看出是允许函数模板重载的

    2.C++编译器优先考虑普通函数

    //实现参数交换
    template<typename T>
    void mySwap(T& t1, T& t2)
    {
        T temp;
        temp = t1;
        t1 = t2;
        t2 = temp;
        cout << "template func" << endl;
    }
    
    void mySwap(int &b, int& a)
    {
        int temp;
        temp = a;
        a = b;
        b = temp;
        cout << "ordinary func" << endl;
    }
    
    void main()
    {
        int a = 16, b = 64;
        mySwap(a, b);
    
        cout << "a:" << a<<endl;
        cout << "b:" << b << endl;
        
        system("pause");
    }
    可以看出模板函数和普通函数都是可以匹配成功的,但是C++编译器却优先选取了普通函数

    3.如果函数模板可以产生一个更好的匹配,那么选择模板

    //实现参数交换
    template<typename T>
    void mySwap(T& t1, T& t2)
    {
        T temp;
        temp = t1;
        t1 = t2;
        t2 = temp;
        cout << "template func" << endl;
    }
    
    void mySwap(int &b, int& a)
    {
        int temp;
        temp = a;
        a = b;
        b = temp;
        cout << "ordinary func" << endl;
    }
    
    void main()
    {
        float a = 16.5, b = 64.6;
        mySwap(a, b);
    
        cout << "a:" << a<<endl;
        cout << "b:" << b << endl;
        
        system("pause");
    }
    可以看出,在符合模板函数参数列表严格匹配的条件下,若是和模板函数更好匹配,那么会去选择模板函数

    4.可以通过空模板实参列表的语法限定编译器只通过模板匹配

    template<typename T>
    void mySwap(T& t1, T& t2)
    {
        T temp;
        temp = t1;
        t1 = t2;
        t2 = temp;
        cout << "template func" << endl;
    }
    
    void mySwap(int &b, int& a)
    {
        int temp;
        temp = a;
        a = b;
        b = temp;
        cout << "ordinary func" << endl;
    }
    
    void main()
    {
        int a = 16, b = 64;
        mySwap(a, b);    //若是不做处理会优先调用普通函数
    
        //下面通过<>类型列表,显示调用模板函数
        mySwap<>(a, b);
    
        cout << "a:" << a<<endl;
        cout << "b:" << b << endl;
        
        system("pause");
    }
    通过空模板<>列表可以显示调用模板函数

    (五)总结

    1.编译器并不是把函数模板处理成能够处理任意类的函数
    2.编译器从函数模板通过具体类型产生不同的函数
    3.编译器会对函数模板进行两次编译:
        在声明的地方对函数模板进行编译
        在调用的地方对参数替换后的代码进行编译

    二:类模板

    (一)单个类模板语法

    //也可以通过类属参数进行直接传参
    template<typename T,int exp1,typename T3>    //类属参数列表写了,可以不用(不会报错),但是既然不用,写他也就没有意义
    class A
    {
    public:
        T t;    //注意:类属参数列表中的参数,至少在类说明中出现一次
    public:
        A(int a)
        {
            this->t = a + exp1;
        }
    
        void getInfo()
        {
            cout <<"getInfo:"<<this->t << endl;
        }
    };
    
    void main()
    {
        A<int,10,int> a(5);    //模板类调用
        a.getInfo();
    
        system("pause");
    }

    (二)继承中的函数模板:派生类必须实例化基类(指定好参数列表)

    template<typename T>
    class A
    {
    public:
        T t;
    public:
        A(T a)
        {
            this->t = a ;
        }
    
        void getInfo()
        {
            cout <<"A getInfo:"<<this->t << endl;
        }
    };
    
    class B :public A<float>
    {
    public:
        int b;
    public:
        B(int n, float m) :A<float>(m)
        {
            b = n;
        }
    
        void getInfo()
        {
            cout << "B getInfo:" << this->b << endl;;
            A<float>::getInfo();
        }
    };
    
    void main()
    {
        B b(5, 6.5);
        b.getInfo();
    
        system("pause");
    }

    总之:子类从模板类继承时,一定要让编译器知道父类的具体类型,才可以进行内存分配。

    (三) 类模板方法在类外部进行定义(上面都是在内部定义)

    template <class 虚拟类型参数>
    函数类型 类模板名<虚拟类型参数>::成员函数名(函数参数列表)
    {
        ....
    }
    template<typename T>
    class A
    {
    public:
        T t;
    public:
        A(T a)
        {
            this->t = a ;
        }
    
        T getInfo();  //需要提前声明
    };
    
    template<class T>  //typename也可以
    T A<T>::getInfo()
    {
        cout << "A outfunc" << endl;
        return this->t;
    }
    
    void main()
    {
        int ret;
        A<int> a(5);
        ret=a.getInfo();
        cout << "ret:" << ret << endl;
        system("pause");
    }

    (四)类模板友元函数使用(声明,实现,调用3个都要注意)

    template<typename T>
    class A
    {
    public:
        T t;
    public:
        A(T a)
        {
            this->t = a ;
        }
    
        T getInfo();
    
        friend A<T> mySub(A<T> &a1, A<T> &a2);  //1.声明
    };
    
    template <typename T>               //2.实现
    A<T> mySub(A<T> &a1, A<T> &a2)
    {
        A<T> a(a1.t - a2.t);
        return a;
    }
    
    template<typename T>
    T A<T>::getInfo()
    {
        cout << "A outfunc" << endl;
        return this->t;
    }
    
    
    void main()
    {
        int ret;
        A<int> a(5);
        A<int> b(2);
    
        //注意友元函数的调用方法
        A<int> c = mySub<int>(a, b);      //3.调用    //返回匿名对象,直接初始化给c
    
        ret=c.getInfo();
        cout << "ret:" << ret << endl;
        system("pause");
    }

  • 相关阅读:
    sas中一些小的选项的含义
    C++变量学习点
    sas,log,output,ods输出管理(html output_object output_statement)
    matlab统计函数
    sas条件判断语句where,if的区别,以及where选项
    sas数组,数组的语法与一些特殊定义,获取维度大小
    sas赋值语句,累加语句,keep,drop,rename,(retain/sum statement)
    解决Xcode 4.3.2的"Could not insert new outlet connection"问题
    网络数据的XML解析
    将UIView中的图像保存到相册
  • 原文地址:https://www.cnblogs.com/ssyfj/p/10777240.html
Copyright © 2011-2022 走看看