zoukankan      html  css  js  c++  java
  • C++ 面向对象编程7 模板

    概念

      模板作用强大且复杂,由于水平有限本文只做简单讲解和使用。模板的作用就是实现类型通用,降低代码的冗余度模板可以为一种算法定义适用不同类型的版本,实现机制:

    1.使用类型参数摆脱类型的限制,丧失了一定的类型安全;
    2.模板要实例化才能使用,实例化由编译器来实现的。
    

    分类

    函数模板

      函数模板就是带类型参数的函数,函数的返回值,局部变量,形式参数都可以使用类型参数,函数模板支持类型推断(形参)。

    函数模板 ---> 实例化 ---> 函数
                 编译
    

    类模板

      类模板就是带类型参数的类,类的成员变量,成员函数,成员类型都可以使用类型参数,类模板不支持类型推断。

    类模板 ---> 实例化 ---> 类 ---> 实例化 ---> 对象
               编译                运行
    

    使用

    函数模板

      语法:

    //函数模板定义
    template<typename T/*类型参数*/....>
    返回值类型  函数模板名(形参列表)
    {
        .......//函数中可以使用类型参数T作为类型
    }
    
    //函数模板的调用
    函数模板名<类型...>(实参);//如果类型参数可以通过实参推断出来,传递的类型参数可以省略
    

    类模板

      语法:

    //类模板的定义
    template<typename T/*类型参数*/....>
    class 类模板名{
        ........//类的成员可以使用类型参数T作为类型    
    };
    
    //类模板的使用
    类模板名<类型...> 对象名; //类模板不支持类型推断
    

    模板的特化

      如果模板对某些特殊的类型的行为需要重新定义,此时可以进行模板特化;比如创建一个用于比较大小的函数模板,无论是int型还是float型、char型都可以通用,但是对于char*(字符串),是不能使用这个模板的,所以需要对这个模板进行特化,当传入的参数是char *则调用重新定义的模板,而不是使用之前通用类型的模板,对于类模板也是一样,因为有一些类型的运算和通用模板不符也需要进行特化,语法如下:

    //函数模板特化
    template<>
    返回值类型  函数模板名<特化的类型...>(形参列表)
    {
        .....//使用特化的类型
    }
    
    //类模板特化
    template<>
    class 类模板名<特化的类型...>{
        ........//类的成员使用特化类型作为类型    
    };
    

      编译器在对模板实例化时,如果原模板和特化模板同时符合,优先选择特化的模板。

    实验程序:

    #include <iostream>
    #include <string>
    #include <cstring>
    
    using namespace std;
    
    //函数模板
    template <typename T>
    T mymax(const T a, const T b)
    {
        return a > b ? a : b;
    }
    
    //函数模板特化
    template<>
    const char * mymax<const char *>(const char *str1, const char *str2)
    {
        return strcmp(str1, str2) > 0 ? str1 : str2;
    }
    
    //类模板
    template <typename T>
    class comparator{
    public:
        comparator(T a, T b):a(a),b(b){};
        T max()
        {
            return a > b ? a : b;
        }
        T min()
        {
            return a > b ? b : a;
        }
    
    private:
        T a;
        T b;
    };
    
    //类模板特化
    template<>
    class comparator<const char* >{
    public:
        comparator(const char *str1, const char *str2):str1(str1),str2(str2){};
        const char *max()
        {
            return strcmp(str1, str2) > 0 ? str1 : str2;
        }
    
    private:
        const char *str1;
        const char *str2;
    };
    
    int main()
    {
        const char *str1 = "abc";
        const char *str2 = "efg";
        
        cout<<"int max:"<<mymax<int>(99, 100)<<endl;
        cout<<"float max:"<<mymax<float>(0.000001, 0.000002)<<endl;
        cout<<"const char *:"<<mymax<const char *>(str1, str2)<<endl;
    
        comparator<int> c1(100, 200);
        cout<<"class int max:"<<c1.max()<<endl;
        cout<<"class int min:"<<c1.min()<<endl;
    
        comparator<float> c2(0.001, 0.002);
        cout<<"class float max :"<<c2.max()<<endl;
        cout<<"class float min :"<<c2.min()<<endl;
    
        comparator<const char *> c3("abc", "efg");
        cout<<"class const char * max:"<<c3.max()<<endl;
    
        return 0;
    }
    

    输出结果:

    类模板的成员特化

      对于类模板而言,既可以进行全类特化,也可以只针对部分与类型相关的成员函数进行特化。成员特化时要保证接口的规则和原通用模板完全一致,语法如下:

    template<>
    返回值类型 类模板名<特化类型...>::成员函数名(形参列表)
    {
        ........//使用特化的类型
    }
    

    实验程序:排序

    #include <iostream>
    #include <cstring>
    #include <string>
    
    using namespace std;
    
    template<typename T>
    class sortor{
    public:
        sortor(T *a, int n)
        {
            this->a = new T[n];
            this->n = n;
    
            for(int i = 0; i < n; i++)
            {
                this->a[i] = a[i];
            }
        }
        ~sortor()
        {
            delete[] this->a;
        }
        void sort()
        {
            int i;
            int j;
    
            for(i = 0; i < n-1; i++)
            {
                bool flag = true;
                for(j = 0; j < n - 1 - i; j++)
                {
                    if (a[j]>a[j+1])
                    {
                        flag = false;
                        T tmp = a[j];
                        a[j] = a[j + 1];
                        a[j + 1] = tmp;
                    }
                }
                //扫描一次没有交换,说明已经排好序了
                if (flag)
                    break;
            }
        }
    
        void print()
        {
            for(int i=0;i<n;i++)
            {
                cout<<a[i]<<" ";
            }
            cout<<endl;
        }
    
    private:
        T *a;   //首地址
        int n;  //长度
    };
    
    //成员特化
    template<>
    void sortor<const char *>::sort()
    {
        int i;
        int j;
    
        for(i = 0;i < n - 1; i++)
        {
            bool flag = true;
            for(j = 0; j < n - 1 - i; j++)
            {
                if(strcmp(a[j], a[j + 1]) > 0)
                {
                    flag = false;
                    const char *tmp = a[j];
                    a[j] = a[j + 1];
                    a[j + 1] = tmp; 
                }
            }
            //扫描一次没有交换,说明已经排序好了
            if(flag)
                break;
        }
    };
    
    int main()
    {
        int arr[] = {5,9,6,8,4,7,1,17,2};
        double d_arr[] = {5.9,6.8,4.0,7.5,3.6,8.9,2.4,9.7,1.3};
        string str_arr1[] = {"ddd","ccc","bbb","eee","aaa"};
        const char *str_arr2[] = {"ddd","ccc","bbb","eee","aaa"};
    
    
        sortor<int> s1(arr, sizeof(arr)/sizeof(arr[0]));
        s1.sort();
        s1.print();
    
        sortor<string> s2(str_arr1,sizeof(str_arr1)/sizeof(str_arr1[0]));
        s2.sort();
        s2.print();
    
        sortor<const char *> s3(str_arr2, sizeof(str_arr2)/sizeof(str_arr2[0]));
        s3.sort();
        s3.print();
    
        return 0;
    }
    

    输出结果:

    类模板的局部特化

      对于具有多个类型参数的类模板,可以只特化其中一部分类型参数,编译器优先选择特化程度最高的版本。

    1.特化一部分类型参数

    template<T1,T2,T3>
    class xxxxx{};
    
    //局部特化
    template<T1,T2>
    class xxxxx<T1,T2,int>{};
    
    tempalte<T1>
    class xxxxx<T1,char,int>{}
    

    2.特化类型参数的特殊关系

    template<T1,T2,T3>
    class xxxxx{};
    
    //局部特化
    template<T1,T2>
    class xxxxx<T1,T2,T2>{};
    

    3.特化指针和数组类型

    template<T1,T2,T3>
    class xxxxx{};
    
    //局部特化
    template<T1,T2,T3>
    class xxxxx<T1*,T2*,T3*>{};
    

    实验程序

    #include <iostream>
    #include <string>
    
    using namespace std;
    
    //通用类模板特化
    template<typename T1, typename T2, typename T3>
    class trib{
    public:
        trib()
        {
            cout<<"trib<T1, T2, T3>"<<endl;
        }
    };
    
    //局部特化
    //1.特化某些类型参数
    template<typename T1, typename T2>
    class trib<T1, T2, int>{
    public:
        trib()
        {
            cout<<"trib<T1, T2, int>"<<endl;
        }
    };
    
    //2.特化类型参数的关系
    template<typename T1, typename T2>
    class trib<T1, T2, T2>{
    public:
        trib()
        {
            cout<<"trib<T1, T2, T2>"<<endl;
        }
    };
    
    //3.特化数组/指针类型
    template<typename T1, typename T2, typename T3>
    class trib<T1*, T2*, T3*>{
    public:
        trib()
        {
            cout<<"trib<T1*,T2*,T2*>"<<endl;
        }
    };
    
    //全特化
    template<>
    class trib<int, char, int>{
    public:
        trib()
        {
            cout<<"Trib<int,char,int>"<<endl;
        }
    };
    
    int main()
    {
        trib<int, double, char> t1;//通用
        trib<double, char, int> t2; //局部特化
        trib<double, double, int> t3; //局部特化
        trib<int, double, double> t4; ////特殊关系特化
        trib<int,char,int> t5; //全特化
        trib<int *,double *,char *> t6; //特化数组/指针
    
        return 0;
    }
    

    输出结果:

    类模板的默认参数

      1.类模板的类型参数可以有默认值,有默认值的类型参数要放到右边,如果实例化时不提供参数的类型,就使用默认值;
      2.后面类型参数的默认值可以使用前面类型参数的值;
      3.非类型参数也可以有默认值。

    实验程序:

    #include <iostream>
    #include <typeinfo>
    
    using namespace std;
    
    //类模板的默认参数
    template <typename T1=int, typename T2=char, int T3=1000>
    class A{
    public:
        static void print_type()
        {
            cout<<typeid(T1).name()<<" "
                <<typeid(T2).name()<<" "
                <<T3<<endl;
        }
    };
    
    template<typename T1, typename T2=T1>
    class B{
    public:
        static void print_type()
        {
            cout<<typeid(T1).name()<<" "
                <<typeid(T2).name()<<endl;        
        }
    };
    
    int main()
    {
        const int num = 10;
    
        A<int, int, num>::print_type();
        A<double, short>::print_type();
        A<string>::print_type();
        A<>::print_type();
    
        B<double>::print_type();
    
        return 0;
    }
    

    输出结果:

    智能指针

      将类类型传入模板,构成智能指针

    实验程序:

    #include <iostream>
    
    using namespace std;
    
    class A{
    public:
        A(){cout<<"A()"<<endl;}
        ~A(){cout<<"~A()"<<endl;}
    
        void show()
        {
            cout<<"showA()"<<endl;
        }
    };
    
    //模板化指针对象
    template<typename T>
    class myauto_ptr{
    public:
        myauto_ptr(T *p=NULL):pdata(p)
        {
    
        }
        myauto_ptr(myauto_ptr<T> &t) //自定义类类型将调用这个构造函数
        {
            this->pdata = t.data;
            t.pdata = NULL;
        }
    
        ~myauto_ptr()
        {
            if(this->pdata)
            {
                delete this->pdata;
                this->pdata = NULL;
            }
        }
        //重载->运算符
        T *operator->()
        {
            return this->pdata;
        }
    
        //重载*运算符
        T& operator*()
        {
            return *this->pdata;
        }
    private:
        //要管理的指针
        T *pdata;
    };
    
    int main()
    {
        int *p_int = new int(10);
        myauto_ptr<int> pi(p_int);
        cout<<*pi<<endl;
    
        A *p_a = new A;
        myauto_ptr<A> pa(p_a);
        pa->show();
        (*pa).show();
    
        return 0;
    }
    

    输入结果:

    待补充:

    模板的继承
    模板的模板成员
    模板的模板参数
    
  • 相关阅读:
    开源数据库
    深度学习TensorFlow笔记——学习率
    深度学习TensorFlow笔记——损失函数
    深度学习TensorFlow笔记
    Oracle常用内置函数
    Oracle数据库自带表或者视图
    Oracle数据库查询所有关键字
    IP代理网址
    时间、日历(time、calendar、datatime)
    selenium常用操作
  • 原文地址:https://www.cnblogs.com/ding-ding-light/p/14590727.html
Copyright © 2011-2022 走看看