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,工程中使用模板特化代替类(函数)重定义;

此文为作者学习唐佐林老师的学习笔记,仅为交流共享之用,由此带来的后果,与作者无关;转载请注明转载出处;难免有错,欢迎指正,联系方式qunchao24@sina.com。
原文地址:https://www.cnblogs.com/sharecenter/p/14694821.html