C++中的数据类模板

1,预备知识:

    1,模板参数可以是数值型参数(非类型参数):

       1,代码示例:

1 template <typename T, int N> 
2 void func()
3 {
4     T a[N];  // 使用模板参数定义局部数组;
5 }
6            
7 func<double, 10>();  // 使用模板时,数值型参数必须是常量,不能是变量;

    2,数值型模板参数的限制:

       1,变量不能作为模板参数;

           1,是变量的话就不满足准确确定的这个本质;

       2,浮点数不能作为模板参数;

           1,浮点数本身不精确;

       3,类对象不能作为模板参数;

           1,类对象编译时不能唯一确定的,同变量一样;

    3,数值型参数本质:模板参数是在编译阶段被处理的单元,因此,在编译阶段必须准确无误的唯一确定;

          

2,有趣的面试题:

    1,用你觉得最高效的方法求 1 + 2 + 3 + ... + N 的值;

       1,等差数列和的方式;

       2,见下面实例;

   

3,数值型模板参数编程实验:

 1 #include <iostream>
 2 #include <string>
 3 
 4 using namespace std;
 5 
 6 /* 验证上面的预备知识 */
 7 template
 8 < typename T, int N >  // 这里用成 double 后,编译器显示:error: 'double' is not a valid type for a template constant parameter
 9 void func()
10 {
11     T a[N] = {0};
12     
13     for(int i=0; i<N; i++)
14     {
15         a[i] = i;
16     }
17     
18     for(int i=0; i<N; i++)
19     {
20         cout << a[i] << endl;
21     }
22 }
23 
24 /* 用最高效的方法验证从 1 加到 n 的和;不用循环和等差数列求和公式 */
25 template
26 < int N >
27 class Sum
28 {
29 public:
30     // static const int VALUE = 0;  // static 后是想定义常量,被 static 修饰后要么放入符号表、要么放到全局数据区; 这个时候 VALUE 已经确定了值,所以直接进入符号表(符号表存储在哪里呢);又因为 VALUE 被 static 修饰了,所以 VALUE 被放入全局数据区;
31     static const int VALUE = Sum<N-1>::VALUE + N;  // 递归定义
32 };
33 
34 /* 定义上述模板类的特化实现,实现递归出口 */
35 template
36 < >
37 class Sum < 1 >
38 {
39 public:
40     static const int VALUE = 1;
41 };
42 
43 int main()
44 {
45     func<int, 10>();  // 打印 0 到 9 这十个数字;这里如果模板参数类型为 double,编译器显示:error: no matching function for call to 'func()';
46     
47     int a = 10;
48     func<int, a>();  // 在这一行编译器显示:
49        // error: 'a' cannot appear in a constant-expression
50        // error: no matching function for call to 'func()'
51                      
52     cout << "1 + 2 + 3 + ... + 10 = " << Sum<10>::VALUE << endl;  // 55;这里没有加减乘除法,也没有函数调用和循环,这里VALUE 是常量,并在编译的时候已经确定,这里效率是最高的;
53     cout << "1 + 2 + 3 + ... + 100 = " << Sum<100>::VALUE << endl;   // 5050
54     
55     return 0;
56 }    

    1,这里的相加求和是在编译器编译程序的时候完成的,编译完程序后,要求的和的值已经确定,在运行的时候,就直接可以访问这个值,不需要做任何的运算和循环,因此效率最高;

    2,这个最高效的求和依赖了模板技术、模板特化技术、数值型模板参数技术;

    3,可以举一反三,得到更多高效的程序写法;

   

4,数组模板类编程实验:

    1,Array.h 文件:

 1 #ifndef _ARRAY_H_  // 防止多次包含头文件;
 2 #define _ARRAY_H_
 3 
 4 template
 5 < typename T, int N >  // 数组元素的类型和大小;
 6 class Array
 7 {
 8     T m_array[N];  // 定义一个实际的数组;
 9 public:
10     int length();
11     bool set(int index, T value);
12     bool get(int index, T& value);
13     T& operator[] (int index);
14     T operator[] (int index) const;  // 数组类对象有可能是 const 对象,这个时候就只能调用 const 函数,所以要定义这个;const 函数只能返回值,不能返回引用;
15     virtual ~Array();  // 有可能被继承
16 };
17 
18 /* 模板类要放在一个文件中,所以实现在下面实现 */
19 
20 template
21 < typename T, int N >
22 int Array<T, N>::length()
23 {
24     return N;
25 }
26 
27 template
28 < typename T, int N >
29 bool Array<T, N>::set(int index, T value)
30 {
31     bool ret = (0 <= index) && (index < N);
32     
33     if( ret )
34     {
35         m_array[index] = value;
36     }
37     
38     return ret;
39 }
40 
41 template
42 < typename T, int N >
43 bool Array<T, N>::get(int index, T& value)
44 {
45     bool ret = (0 <= index) && (index < N);
46     
47     if( ret )
48     {
49         value = m_array[index];
50     }
51     
52     return ret;
53 }
54 
55 template
56 < typename T, int N >
57 T& Array<T, N>::operator[] (int index)
58 {
59     return m_array[index];
60 }
61 
62 template
63 < typename T, int N >
64 T Array<T, N>::operator[] (int index) const
65 {
66     return m_array[index];
67 }
68 
69 template
70 < typename T, int N >
71 Array<T, N>::~Array()
72 {
73 
74 }
75 
76 #endif

    2,应用:

 1 #include <iostream>
 2 #include <string>
 3 #include "Array.h"
 4 
 5 using namespace std;
 6 
 7 int main()
 8 {
 9     Array<double, 5> ad;
10     
11     for(int i=0; i<ad.length(); i++)
12     {
13         ad[i] = i * i;
14     }
15     
16     for(int i=0; i<ad.length(); i++)
17     {
18         cout << ad[i] << endl;
19     }
20     
21     return 0;
22 }

   

5,堆数组模板类编程实验:

 1,HeapArray.h 文件:

  1 #ifndef _HEAPARRAY_H_
  2 #define _HEAPARRAY_H_
  3 
  4 template
  5 < typename T >
  6 class HeapArray
  7 {
  8 private:
  9     int m_length;
 10     T* m_pointer;
 11     
 12     HeapArray(int len);
 13     HeapArray(const HeapArray<T>& obj);
 14     bool construct();
 15 public:
 16     static HeapArray<T>* NewInstance(int length); 
 17     int length();
 18     bool get(int index, T& value);
 19     bool set(int index ,T value);
 20     T& operator [] (int index);
 21     T operator [] (int index) const;  // 有可能有 const 对象;
 22     HeapArray<T>& self();
 23     ~HeapArray();  // 这个时候构造函数是 private 的,也就是 HeapArray 类不希望被继承,所以说没有必要将它声明为 virtual 的;
 24 };
 25 
 26 /* 实现要在同一个文件中 */
 27 
 28 template
 29 < typename T >
 30 HeapArray<T>::HeapArray(int len)
 31 {
 32     m_length = len;
 33 }
 34 
 35 template
 36 < typename T >
 37 bool HeapArray<T>::construct()
 38 {   
 39     m_pointer = new T[m_length];
 40     
 41     return m_pointer != NULL;
 42 }
 43 
 44 template
 45 < typename T >
 46 HeapArray<T>* HeapArray<T>::NewInstance(int length) 
 47 {
 48     HeapArray<T>* ret = new HeapArray<T>(length);
 49     
 50     if( !(ret && ret->construct()) ) 
 51     {
 52         delete ret;
 53         ret = 0;
 54     }
 55         
 56     return ret;
 57 }
 58 
 59 template
 60 < typename T >
 61 int HeapArray<T>::length()
 62 {
 63     return m_length;
 64 }
 65 
 66 template
 67 < typename T >
 68 bool HeapArray<T>::get(int index, T& value)
 69 {
 70     bool ret = (0 <= index) && (index < length());
 71     
 72     if( ret )
 73     {
 74         value = m_pointer[index];
 75     }
 76     
 77     return ret;
 78 }
 79 
 80 template
 81 < typename T >
 82 bool HeapArray<T>::set(int index, T value)
 83 {
 84     bool ret = (0 <= index) && (index < length());
 85     
 86     if( ret )
 87     {
 88         m_pointer[index] = value;
 89     }
 90     
 91     return ret;
 92 }
 93 
 94 template
 95 < typename T >
 96 T& HeapArray<T>::operator [] (int index)
 97 {
 98     return m_pointer[index];
 99 }
100 
101 template
102 < typename T >
103 T HeapArray<T>::operator [] (int index) const
104 {
105     return m_pointer[index];
106 }
107 
108 template
109 < typename T >
110 HeapArray<T>& HeapArray<T>::self()
111 {
112     return *this;
113 }
114 
115 template
116 < typename T >
117 HeapArray<T>::~HeapArray()
118 {
119     delete[]m_pointer;
120 }
121 
122 #endif

    2,应用:

 1 #include <iostream>
 2 #include <string>
 3 #include "HeapArray.h"
 4 
 5 using namespace std;
 6 
 7 int main()
 8 {   
 9     HeapArray<char>* pai = HeapArray<char>::NewInstance(10);
10     
11     if( pai != NULL )
12     {
13         HeapArray<char>& ai = pai->self();
14         
15         for(int i=0; i<ai.length(); i++)
16         {
17             ai[i] = i + 'a';
18         }
19         
20         for(int i=0; i<ai.length(); i++)
21         {
22             cout << ai[i] << endl;
23         }
24     }
25     
26     delete pai;
27     
28     return 0;
29 }

   

6,小结:

    1,模板参数可以是数值型参数;

    2,数值型模板参数必须在编译期间唯一确定;

    3,数组类模板是基于数值型模板参数实现的;

    4,数组类模板是简易的线性表数据结构;

posted @ 2019-05-24 16:53 子宇24 阅读(...) 评论(...) 编辑 收藏