第六十课、数组类模板

一、数值型参数(类型参数)

1、模板参数可以是数值型参数

2、数值型模板参数的限制

(1)、变量不能作为模板参数

(2)、浮点数不能作为模板参数

(3)、类对象不能作为模板参数

(4)、等等

3、数值型参数的本质

(1)、模板参数是在编译阶段被处理的单元,因此,在编译阶段必须准确无误唯一确定

#include <iostream>
#include <string>

using namespace std;

template < typename T, int N>
void func()
{
    T a[N] = {0};
    
    for (int i=0; i<N; i++)
    {
        a[i] = i;
    }
    
    for (int i=0; i<N; i++)
    {
        cout << a[i] << endl;
    }
}

template <int N>
class Sum
{
public:
    //注意以下语句采用递归定义,即当调用Sum<N>::VALUE时,
    //编译器认为其值等于Sum<N-1>::VALUE + N;于是就出现了
    //递归,直至Sum<1>时会找到后面特化的类模定义,因那里
    //Sum<1>::VALUE=1,于是递归结束。
    //注意,在这程中,会依次产生Sum<100>、Sum<99>、...、Sum<1>
    //等100个类,而每个类里面都有一个静态成员变量VALUE值,因其
    //位于不同的类中,本质上在静态数据中会开辟100多个int型空间
    //来存储这些变量。在编译器会进行优化,把中间这些不用的类给
    //丢弃,最保存最终的结果,即内存中只有一个静态VALUE变量的值。
    static const int VALUE = Sum<N-1>::VALUE + N;
};

template<>
class Sum<1>
{
public:
    //以下语句在声明和定义起并对VALUE进行了初始化。这是合法的
    //1. 如果只有单独的static int VALUE为什么不能直接初始化?
    //   因为C++里声明和定义是分开的,当编译器看到那样的语句时
    //   会认为这是声明,并没有定义,也就是空间还没分配好,需要在
  //类的外部先另外分配空间才能初始化

//2. 如果只有const int VALUE为什么也不能直接初始化? // 这也是同样的道理,这里的VALUE属于对象,而对象要用使用时 // 才分配空间,而在这里是无法分配空间的。可以在构造函数的初始化列表中初始化
  // const在类不同对象中可能值不一样,也就是说const在单个对象中是不可变的,但对于类是可变的
//3. static const int VALUE = 1;为什么这样的语句合法? // 当这两种的结合,其意义就跟一般的全局常量差不多,
  //进入符号表并且初始化为1
static const int VALUE = 1; }; int main() { cout << "1 + 2 + 3 + ...+ 10 = " << Sum<10>::VALUE << endl;//VALUE的值在编译期就确定了,所有非常高效 cout << "1 + 2 + 3 + ...+ 100 = " << Sum<100>::VALUE << endl; return 0; }

用数组类模板来实现数组类:

//Array.h

#ifndef  _ARRAY_H_
#define  _ARRAY_H_
template
<typename T, int N>
class Array
{
protected:
    T a[N];
public:
    int length();
    int length()const;//const对象时用,与上面的函数构造重载
    bool get(int index, T& value);
    bool set(int index, T value);
    T& operator [] (int index);  //返回引用可以做左值
    virtual ~Array();//允许被继承,声明为虚函数
};

#endif

template
<typename T, int N>
int Array<T, N>::length()
{
    return N;
}

template
<typename T, int N>
int Array<T, N>::length()const
{
    return N;
}


template
<typename T, int N>
bool Array<T, N>::set(int index, T value)
{
    bool ret = (0 < index) && (index < length());
    
    if(ret)
    {
        a[index] = value;
    }
    
    return ret;
}

template
<typename T, int N>
bool Array<T, N>::get(int index, T& value)
{
bool ret = (0 < index) && (index < length());
    
    if(ret)
    {
        value = a[index];
    }
    
    return ret;
}

template
<typename T, int N>
T& Array<T, N>::operator [] (int index)
{
    return a[index];
}

template
<typename T, int N>
Array<T, N>::~Array()
{
};

//HeapArray.h

#ifndef _HEAPArray_H_
#define _HEAPArray_H_

template
< typename T >
class HeapArray
{
private:
    T* m_poiter; 
    int m_length;
    
    HeapArray(int length);//构造函数私有,不允许继承
    HeapArray(const HeapArray<T>& obj);
    bool construct();
public:
    static HeapArray<T>* NewInstance(int length);
    int length();
    int length()const;//const对象时用
    bool get(int index, T& value);
    bool set(int index, T value);
    T& operator [] (int index);
    HeapArray<T>& self();   
    ~HeapArray();
};

template
< typename T >
HeapArray< T >::HeapArray(int length)
{
    m_length = length;
}

template
< typename T >
bool HeapArray< T >::construct()
{
    
    m_poiter = new T[m_length];

    return m_poiter != NULL;
}

template
< typename T >
HeapArray< T >* HeapArray< T >::NewInstance(int length)
{
    HeapArray< T >* ret = new HeapArray(length);
    
    if(!(ret && (ret->construct())))
    {
        delete ret;
        ret = NULL;
    }
    
    return ret;
}

template
< typename T >
int HeapArray< T >::length()
{
    return m_length;
}

template
< typename T >
int HeapArray< T >::length()const
{
    return m_length;
}

template
< typename T >
bool HeapArray< T >::get(int index, T& value)
{
    bool ret = (0 < index) && (index < length());
    if(ret)
    {
        value = m_poiter[index];
    }
    
    return ret;
}

template
< typename T >
bool HeapArray< T >::set(int index, T value)
{
    bool ret = (0 < index) && (index < length());
    if(ret)
    {
        m_poiter[index] = value;
    }
    
    return ret;
}

template
< typename T >
T& HeapArray< T >::operator [] (int index)
{
    return m_poiter[index];
}

template
< typename T >
HeapArray<T>& HeapArray< T >::self()
{
    return *this;
}  


template
< typename T >
HeapArray< T >::~HeapArray()
{
    delete[] m_poiter;
}

#endif

//main.cpp

#include<iostream>
#include"Array.h"
#include"HeapArray.h"

using namespace std;

int main()
{
/********************************Array*********************************/
    Array< double, 5 > a1;
    
    int length = a1.length();    
    cout << "a1.length() = " << a1.length() << endl;
    
    for(int i=0; i<a1.length(); i++)
    {
        a1[i] = i + 1;
    }
    
    for(int i=0; i<a1.length(); i++)
    {
        cout << a1[i] << endl;
    }
    
    const Array< int, 10 > a2;
    cout << "a1.length() = " << a2.length() << endl;
    cout << endl;
/*****************************HeapArray*********************************/  
  
    HeapArray<int>* a3 =  HeapArray< int > :: NewInstance(15);  
    if(a3 != NULL)
    {
        HeapArray<int>& array = a3->self();
        cout << "array.length() = " << array.length() << endl;
        
        for(int i=0; i<array.length(); i++)
        {
            array[i] = i + 1;
        }
        
        for(int i=0; i<array.length(); i++)
        {
            cout << array[i] << endl;
        } 
    }
    
    delete a3;//记得要销毁对象

    
    return 0;
}

二、小结

(1)、模板参数可以是数值型参数

(2)、数值型参数必须在编译期唯一确定

(3)、数组类模板是基于数值型模板参数实现的

(4)、数组类模板是简易的线性表数据结构

原文地址:https://www.cnblogs.com/gui-lin/p/6377593.html