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

  • 相关阅读:
    转:windows通过VNC访问远程ubuntu14.04 【 server】服务器
    【转】研究了代码质量后,开发速度提高了2倍,bug减少了15倍
    【转】PuTTY的ppk密钥与OpenSSH密钥之间的相互转换
    【转】outlook配置腾讯企业邮箱(腾讯企业邮箱imap服务器地址)
    【转】YApi结合swag管理和生成go项目restful API文档
    [转] 超高效!SwaggerYapi的秘密
    【转】SSH 远程登录很慢的解决方法
    [转]go语言io reader_如何从io.Reader 中读数据
    eslint 支持多个三目表达式
    33
  • 原文地址:https://www.cnblogs.com/dishengAndziyu/p/10919050.html
Copyright © 2020-2023  润新知