• C++中类模板的深入理解


    1,多参数类模板:

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

             1,代码示例:

    1 template <typename T1, typename T2>
    2 class Test
    3 {
    4 public:
    5     void add(T1 a, T2 a);
    6 };
    7 
    8 Test<int, float> t;

        2,类模板可以被特化:

     

                   1,指定类模板的特定实现;

                   2,部分类型参数必须显示指定;

                   3,根据类型参数分开实现类模板;

           3,类模板的特化类型:

     

                1,部分特化 - 用特定规则约束类型参数;

                     1,上面的为部分特化;

                2,完全特化 - 完全显示指定类型参数;

           4,类模板的特化编程实验:

     1 #include <iostream>
     2 #include <string>
     3 
     4 using namespace std;
     5 
     6 template
     7 < typename T1, typename T2 >
     8 class Test
     9 {
    10 public:
    11     void add(T1 a, T2 b)
    12     {
    13         cout << "void add(T1 a, T2 b)" << endl;
    14         cout << a + b << endl;
    15     }
    16 };
    17 
    18 /* 关于上述第一个类模板的特殊实现,关于指针的特化实现 */
    19 template
    20 < typename T1, typename T2 >
    21 class Test < T1*, T2* >      // 关于指针的特化实现
    22 {
    23 public:
    24     void add(T1* a, T2* b)
    25     {
    26         cout << "void add(T1* a, T2* b)" << endl;
    27         cout << *a + *b << endl;
    28     }
    29 };
    30 
    31 /* 定义上述第一个类模板的特殊实现,即当Test 类模板的两个类型参数完全相同时,使用这个实现;编译器并不认为在这里重新定义了一个新的模板,它认为这里是在定义第一个类模板的特殊实现;这里是部分特化; 
    32 */
    33 template
    34 < typename T >
    35 class Test < T, T >    // Test 类模板的两个类型参数完全相同时,使用这个实现;
    36 {
    37 public:
    38     void add(T a, T b)
    39     {
    40         cout << "void add(T a, T b)" << endl;
    41         cout << a + b << endl;
    42     }
    43     
    44     void print()  // 特化实现可以重新定义新的函数;
    45     {
    46         cout << "class Test < T, T >" << endl;
    47     }
    48 };
    49 
    50 /* 定义上述第一个类模板的特殊实现,当 T1 == void* 并且 T2 == void* 时,使用这个实现; */
    51 template
    52 <  >  // 没有泛指类型; 
    53 class Test < void*, void* >    // 当 T1 == void* 并且 T2 == void* 时
    54 {
    55 public:
    56     void add(void* a, void* b)
    57     {
    58         cout << "void add(void* a, void* b)" << endl;
    59         cout << "Error to add void* param..." << endl;
    60     }
    61 };
    62 
    63 int main()
    64 {  
    65     Test<int, float> t1;  // 使用第一个类模板;
    66     Test<long, long> t2;  // 使用第三个类模板,特化实现;
    67     Test<void*, void*> t3;  // 使用第四个类模板,特化实现;
    68     
    69     t1.add(1, 2.5);  // void add(T1 a, T2 b) 3.5;
    70     
    71     t2.add(5, 5);  // void add(T a, Tb) 10;
    72     t2.print();  // class Test < T, T >
    73     
    74     t3.add(NULL, NULL);  // void add(void* a, void* b);Error to add void* param...;
    75     
    76     Test<int*, double*> t4;  // 未有定义指针特化时,编译器显示 14 行:error: invalid operands of types 'int*' and 'double*' to binary 'operator+';
    77                             // 特化指针后,打印 void add(T1* a, T2* b);
    78     int a = 1;
    79     double b = 0.1;
    80     
    81     t4.add(&a, &b);  // 1.1
    82     
    83     return 0;
    84 }

                1,类模板的特化实现表象上面好像定义了不同的类模板,但其实我们仅仅是根据需要将一个类模板分开成不同的情况来实现;

                2,编译器编译过后根据我们使用的类型参数来决定究竟是哪一种实现;

           5,类模板特化注意事项:

                1,特化只是模板的分开实现:

                     1,本质上是同一个类模板;

                     2,仅仅是将模板根据需要分开来实现;

                2,特化类模板的使用方式是统一的;

                     1,必须显示指定每一个类型参数;

              

    2,类模板特化与重定义有区别吗?函数模板可以特化吗?

        1,有区别;

       

    3,特化的深度分析:

        1,重定义和特化的不同:

            1,重定义:

                 1,一个类模板和一个新类(或者两个类模板);

                      1,重定义本质是要么是实现了两个类模板,要么是一个类模板加上 一个新的类;

                      2,特化本质是只实现同一个类模板,特化的目的仅仅是考虑一些特殊的情况类模板应该如何工作;

                  2,使用的时候需要考虑如何选择的问题;

                      1,使用的时候没有统一的方式,要选择用类模板的种类或用新的类;

            2,特化:

                 1,以统一的方式使用类模板和特化类;

                 2,编译器自动优先选择特化类;

                      1,能用特化就不要重定义;

        2,函数模板只支持类型参数完全特化:

            1,代码示例:

     1 template < typename T>  // 函数模板定义
     2 bool Equal(T a, T b)
     3 {
     4     return a == b;
     5 }
     6            
     7 template < >  // 函数模板完全特化
     8 bool Equal<void *>(void* a, void* b)
     9 {
    10     return a == b;
    11 }

        3,特化的深入理解编程实验:

     1 #include <iostream>
     2 #include <string>
     3 
     4 using namespace std;
     5 
     6 /* 以下是类模板的重定义实现 */ 
     7 template
     8 < typename T1, typename T2 >
     9 class Test
    10 {
    11 public:
    12     void add(T1 a, T2 b)
    13     {
    14         cout << "void add(T1 a, T2 b)" << endl;
    15         cout << a + b << endl;
    16     }
    17 };
    18 
    19 /*
    20 template
    21 <  >
    22 class Test < void*, void* >    // 当 T1 == void* 并且 T2 == void* 时
    23 {
    24 public:
    25     void add(void* a, void* b)
    26     {
    27         cout << "void add(void* a, void* b)" << endl;
    28         cout << "Error to add void* param..." << endl;
    29     }
    30 };
    31 */
    32 
    33 /* 类模板的重定义,重新实现上面注释的模板特化,处理指针相加 */
    34 class Test_Void
    35 {
    36 public:
    37     void add(void* a, void* b)
    38     {
    39         cout << "void add(void* a, void* b)" << endl;
    40         cout << "Error to add void* param..." << endl;
    41     }
    42 };
    43 
    44 
    45 /* 以下是函数模板的特化实验 */ 
    46 
    47 template
    48 < typename T >
    49 bool Equal(T a, T b)
    50 {
    51     cout << "bool Equal(T a, T b)" << endl;
    52     
    53     return a == b;
    54 }
    55 
    56 /* 函数完全特化解决浮点数比较问题 */
    57 template
    58 < >
    59 bool Equal<double>(double a, double b)
    60 {
    61     const double delta = 0.00000000000001;
    62     double r = a - b;
    63     
    64     cout << "bool Equal<double>(double a, double b)" << endl;
    65     
    66     return (-delta < r) && (r < delta);
    67 }
    68 
    69 /* 直接重载 */
    70 bool Equal(double a, double b)
    71 {
    72     const double delta = 0.00000000000001;
    73     double r = a - b;
    74     
    75     cout << "bool Equal(double a, double b)" << endl;
    76     
    77     return (-delta < r) && (r < delta);
    78 }
    79 
    80 int main()
    81 {  
    82     Test<void*, void*> t3;  // 这里错误了,要用 Test_Void t3; 这样的 定义方式,因为重定义了类的实现方式,注销了模板特化方式;写代码时,要时刻考虑究竟是要使用类模板 还是要使用新类,这就是弊端,所以能特化时,就不要重新定义、重新实现;
    83                             
    84     cout << Equal( 1, 1 ) << endl;  // bool Equal(T a, T b) 1
    85     cout << Equal<>( 0.001, 0.001 ) << endl;  // 用相等符号比较两个浮点数是否相等是有问题的;用了特化后:bool Equal<double>(double a, double b) 1
    86     cout << Equal( 0.001, 0.001 ) << endl;  // bool Equal(double a, double b) 1;这里调用全局重载函数,因为编译器会优先寻找全局重载函数;
    87                                             
    88     return 0;
    89 }

        4,工程中的建议:

             1,当需要重载函数模板时,优先考虑使用模板特化;当模板特化无法满足需求,再使用函数重载!

          

    4,小结:

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

        2,类模板可以被部分特化和完全特化;

        3,特化的本质是模板的分开实现;

        4,函数模板只支持完全特化;

        5,工程中使用模板特化代替类(函数)重定义;

  • 相关阅读:
    建立一个能持续处理的C/S网络程序
    建立一个可以不停地接收客户端新的连接,但不能处理复杂的业务的C/S网络程序
    归并排序
    堆排序
    计数排序
    不要在PHP7中踩这些坑
    关于生活学习
    topthink/think-swoole 扩展包的使用 之 WebSocket
    PHP 三元运算符
    topthink/think-swoole 扩展包的使用 之 Task
  • 原文地址:https://www.cnblogs.com/dishengAndziyu/p/10918826.html
Copyright © 2020-2023  润新知