C++中的数据类模板
Posted dishengandziyu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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,数组类模板是简易的线性表数据结构;
以上是关于C++中的数据类模板的主要内容,如果未能解决你的问题,请参考以下文章