C++中支持原生数组,但由于原生数组的天然缺陷(不能获取长度信息、越界访问不会报错...),我们有必要来开发自己的数组类,从而解决这些问题。
数组类的继承关系如图:
19.数组类的实现_1
19.1.抽象类模板Array
需求分析:
1、由于线性表,不能作为数组直接使用,我们需要自己实现一个数组类来代替原生数组。
2、解决原生数组越界访问不会报错的问题
3、提供数组的长度信息
19.2.Array设计要点:
- 抽象类模本,存储空间的位置和大小由子类指定。
- 重载数组操作符,并判断访问下标是否越界(合法)
- 提供数组长度信息的抽象访问函数
- 提供数组对象间的复制操作(通过重载拷贝构造函数和赋值操作符完成)
template < typename T > class Array : public Object { protected: T *m_array; public: T& operator [] (int index) T operator [] (int index) const bool get(int index, const T& e) bool set(int index, const T& e) virtual int length(void) = 0; };
19.2.1. Array的实现
#ifndef ARRRY_H
#define ARRRY_H
#include "Object.h"
#include "Exception.h"
namespace DTLib
{
template < typename T >
class Array : public Object
{
protected:
T *m_array;
public:
T& operator [] (int index)
{
if( (index>=0) && (index<length()) )
{
return m_array[index];
}
else
{
THROW_EXCEPTION(IndexOutOfBoundsException, "array index out of range...");
}
}
T operator [] (int index) const
{
return const_cast<Array<T>&>(*this)[index];
}
bool get(int index, const T& e)
{
bool ret = (index>=0) && (index<length());
if( ret )
{
e = m_array[index];
}
return ret;
}
bool set(int index, const T& e)
{
bool ret = (index>=0) && (index<length);
if( ret )
{
m_array[index] = e;
}
return ret;
}
virtual int length(void) = 0;
};
}
#endif // ARRRY_H
19.3.StaticArray的实现
设计要点:
- 封装原生数组;
- 使用模板参数决定数组大小
- 实现函数返回数组长度
- 拷贝构造和赋值重载
template < typename T, int N > class StaticArray : public Array<T> protected: T m_space[N]; public: StaticArray() // 提供拷贝构造喊赋值重载函数,实现数组的拷贝 StaticArray(const StaticArray<T, N>& obj) T& operator = (const StaticArray<T, N>& obj) int length(void) };
19.3.1. StaticArray的实现
#ifndef STATICARRAY_H
#define STATICARRAY_H
#include "Array.h"
namespace DTLib
{
template <typename T, int N>
class StaticArray : public Array<T>
{
protected:
T m_space[N];
public:
StaticArray()
{
this->m_array = m_space;
}
StaticArray(const StaticArray<T, N>& obj)
{
this->m_array = m_space;
for(int i=0; i<length();i++) // 数组元素拷贝
{
m_space[i] = obj.m_space[i];
}
}
T& operator ==(const StaticArray<T, N>& obj)
{
if(this != &obj)
{
this->m_array = m_space;
for(int i=0; i<length();i++)
{
m_space[i] = obj.m_space[i];
}
}
}
int length(void)
{
return N;
}
};
}
#endif // STATICARRAY_H
20.数组类的实现_2
20.1.DynamicArray的实现
设计要点:类模板
- 动态确定内部数组空间的大小
- 实现函数返回数组的长度
- 拷贝构造和赋值操作
template < typename T > class DynamicArray : public Array<T> { protected: int m_length; public: DynamicArray(int length) DynamicArray(const DynamicArray<T>& obj) DynamicArray<T>& operator = (const DynamicArray<T>& obj) void resize(int length) ~DynamicArray() };
20.2.DynamicArray代码优化
DynamicArray类中的函数实现存在重复的逻辑,可以进行代码优化。
重复代码逻辑的抽象:
— init 函数中实现对象构造时的初始化操作
— copy 函数负责从堆空间中申请内存,并执行拷贝构造操作
— updata 将指定的堆空间作为内部存储数组使用20.2.1. DynamicArray实现
#ifndef DYNAMICLIST_H
#define DYNAMICLIST_H
#include "SeqList.h"
namespace DTLib
{
template <typename T>
class DynamicList : public SeqList<T>
{
protected:
int m_capacity;
public:
DynamicList(int capacity)
{
this->m_array = new T[capacity];
if(this->m_array != NULL)
{
this->m_length = 0;
this->m_capacity = capacity;
}
else
{
THROW_EXCEPTION(NoEnoughMemoryException,"No memory to create DynamicList object ...");
}
}
int capacity()const
{
return m_capacity;
}
void resize(int capacity)
{
if(capacity != m_capacity)
{
T* array = new T[capacity];
if(array != NULL)
{
int length = (this->m_length < capacity ? this->m_length : capacity);
for(int i=0;i<length;i++)
{
array[i] = this->m_array[i];
}
T* temp = this->m_array;
this->m_array = array;
this->m_length = length;
this->m_capacity = capacity;
delete[] temp;
}
else
{
THROW_EXCEPTION(NoEnoughMemoryException,"No memory to create DynamicList object ...");
}
}
}
~DynamicList()
{
delete[] this->m_array;
}
};
}
#endif // DYNAMICLIST_H
总结:
- StaticArray通过封装原生数组的方式,实现数组类
- DynamicArray动态申请堆空间,使得数组长度动态可变
- 数组对象能够代替原生数组,并且使用上更安全
- 代码优化时项目开发必不可少的环节
原文地址:http://blog.51cto.com/11134889/2126831
时间: 2024-10-17 19:18:40