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,数组类模板是简易的线性表数据结构;
上一篇: Linux系统禁止root账号远程登录
下一篇: 身份证验证PHP类