欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

C++中的数据类模板

程序员文章站 2022-09-27 23:31:31
1,预备知识: 1,模板参数可以是数值型参数(非类型参数): 1,代码示例: 2,数值型模板参数的限制: 1,变量不能作为模板参数; 1,是变量的话就不满足准确确定的这个本质; 2,浮点数不能作为模板参数; 1,浮点数本身不精确; 3,类对象不能作为模板参数; 1,类对象编译时不能唯一确定的,同变量 ......

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,数组类模板是简易的线性表数据结构;