数据结构开发(4):数组类的创建
0.目录
1.Array
2.StaticArray
3.DynamicArray
4.小结
1.Array
本节目标:
- 完成 Array 类的具体实现
需求分析:
- 创建数组类代替原生数组的使用
- 数组类包含长度信息
- 数组类能够主动发现越界访问
Array 设计要点:
- 抽象类模板,存储空间的位置和大小由子类完成
- 重载数组操作符,判断访问下标是否合法
- 提供数组长度的抽象访问函数
- 提供数组对象间的复制操作
Array 类的声明:
(在StLib中实现Array.h)
#ifndef ARRAY_H
#define ARRAY_H
#include "Object.h"
#include "Exception.h"
namespace StLib
{
template <typename T>
class Array : public Object
{
protected:
T* m_array;
public:
virtual bool set(int i, const T& e)
{
bool ret = ((0 <= i) && (i < length()));
if( ret )
{
m_array[i] = e;
}
return ret;
}
virtual bool get(int i, T& e) const
{
bool ret = ((0 <= i) && (i < length()));
if( ret )
{
e = m_array[i];
}
return ret;
}
// 数组访问操作符
T& operator[] (int i)
{
if( (0 <= i) && (i < length()) )
{
return m_array[i];
}
else
{
THROW_EXCEPTION(IndexOutOfBoundsException, "Parameter i is invalid ...");
}
}
T operator[] (int i) const
{
return (const_cast<Array<T>&>(*this))[i];
}
virtual int length() const = 0;
};
}
#endif // ARRAY_H
2.StaticArray
本节目标:
- 完成 StaticArray 类的具体实现
StaticArray 设计要点
- 类模板
- 封装原生数组
- 使用模板参数决定数组大小
- 实现函数返回数组长度
- 拷贝构造和赋值操作
StaticArray 类的声明:
(在StLib中实现StaticArray.h)
#ifndef STATICARRAY_H
#define STATICARRAY_H
#include "Array.h"
namespace StLib
{
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<N; i++)
{
m_space[i] = obj.m_space[i];
}
}
StaticArray<T, N>& operator= (const StaticArray<T, N>& obj)
{
if( this != &obj )
{
for(int i=0; i<N; i++)
{
m_space[i] = obj.m_space[i];
}
}
return *this;
}
int length() const
{
return N;
}
};
}
#endif // STATICARRAY_H
main.cpp测试
#include <iostream>
#include "StaticArray.h"
using namespace std;
using namespace StLib;
int main()
{
StaticArray<int, 5> s1;
for(int i=0; i<s1.length(); i++)
{
s1[i] = i * i;
}
for(int i=0; i<s1.length(); i++)
{
cout << s1[i] << endl;
}
cout << endl;
StaticArray<int, 5> s2;
s2 = s1;
for(int i=0; i<s2.length(); i++)
{
cout << s2[i] << endl;
}
return 0;
}
运行结果为:
0
1
4
9
16
0
1
4
9
16
3.DynamicArray
本节目标:
- 完成 DynamicArray 类的具体实现
DynamicArray 设计要点
- 类模板
- 动态确定内部数组空间的大小
- 实现函数返回数组长度
- 拷贝构造和赋值操作
DynamicArray 类的声明:
(在StLib中实现DynamicArray.h)
#ifndef DYNAMICARRAY_H
#define DYNAMICARRAY_H
#include "Array.h"
#include "Exception.h"
namespace StLib
{
template <typename T>
class DynamicArray : public Array<T>
{
protected:
int m_length;
public:
DynamicArray(int length)
{
this->m_array = new T[length];
if( this->m_array != NULL )
{
this->m_length = length;
}
else
{
THROW_EXCEPTION(NoEnoughMemoryException, "No memory to create DynamicArray object ...");
}
}
DynamicArray(const DynamicArray<T>& obj)
{
this->m_array = new T[obj.m_length];
if( this->m_array != NULL )
{
this->m_length = obj.m_length;
for(int i=0; i<obj.m_length; i++)
{
this->m_array[i] = obj.m_array[i];
}
}
else
{
THROW_EXCEPTION(NoEnoughMemoryException, "No memory to create DynamicArray object ...");
}
}
DynamicArray<T>& operator= (const DynamicArray<T>& obj)
{
if( this != &obj )
{
T* array = new T[obj.m_length];
if( array != NULL )
{
for(int i=0; i<obj.m_length; i++)
{
array[i] = obj.m_array[i];
}
T* temp = this->m_array;
this->m_array = array;
this->m_length = obj.m_length;
delete[] temp;
}
else
{
THROW_EXCEPTION(NoEnoughMemoryException, "No memory to copy object ...");
}
}
}
int length() const
{
return m_length;
}
void resize(int length) // 动态重置数组的长度
{
if( length != m_length )
{
T* array = new T[length];
if( array != NULL )
{
int size = (length < m_length ? length : m_length);
for(int i=0; i<size; i++)
{
array[i] = this->m_array[i];
}
T* temp = this->m_array;
this->m_array = array;
this->m_length = length;
delete[] temp;
}
else
{
THROW_EXCEPTION(NoEnoughMemoryException, "No memory to resize object ...");
}
}
}
~DynamicArray()
{
delete[] this->m_array;
}
};
}
#endif // DYNAMICARRAY_H
main.cpp测试
#include <iostream>
#include "DynamicArray.h"
using namespace std;
using namespace StLib;
int main()
{
DynamicArray<int> s1(5);
for(int i=0; i<s1.length(); i++)
{
s1[i] = i * i;
}
for(int i=0; i<s1.length(); i++)
{
cout << s1[i] << endl;
}
cout << endl;
DynamicArray<int> s2(10);
s2 = s1;
s2.resize(3);
for(int i=0; i<s2.length(); i++)
{
cout << s2[i] << endl;
}
return 0;
}
运行结果为:
0
1
4
9
16
0
1
4
问题:
DynamicArray 类中的函数实现存在重复的逻辑,如何进行代码优化?
重复代码逻辑的抽象
- init
- 对象构造时的初始化操作
- copy
- 在堆空间中申请新的内存,并执行拷贝操作
- update
- 将指定的堆空间作为内部存储数组使用
动态数组的优化(DynamicArray.h):
优化DynamicArray.h
#ifndef DYNAMICARRAY_H
#define DYNAMICARRAY_H
#include "Array.h"
#include "Exception.h"
namespace StLib
{
template <typename T>
class DynamicArray : public Array<T>
{
protected:
int m_length;
T* copy(T* array, int len, int newLen)
{
T* ret = new T[newLen];
if( ret != NULL )
{
int size = (len < newLen) ? len : newLen;
for(int i=0; i<size; i++)
{
ret[i] = array[i];
}
}
return ret;
}
void update(T* array, int length)
{
if( array != NULL )
{
T* temp = this->m_array;
this->m_array = array;
this->m_length = length;
delete[] temp;
}
else
{
THROW_EXCEPTION(NoEnoughMemoryException, "No memory to update DynamicArray object ...");
}
}
void init(T* array, int length)
{
if( array != NULL )
{
this->m_array = array;
this->m_length = length;
}
else
{
THROW_EXCEPTION(NoEnoughMemoryException, "No memory to create DynamicArray object ...");
}
}
public:
DynamicArray(int length)
{
init(new T[length], length);
}
DynamicArray(const DynamicArray<T>& obj)
{
init(copy(obj.m_array, obj.m_length, obj.m_length), obj.m_length);
}
DynamicArray<T>& operator= (const DynamicArray<T>& obj)
{
if( this != &obj )
{
update(copy(obj.m_array, obj.m_length, obj.m_length), obj.m_length);
}
return *this;
}
int length() const
{
return m_length;
}
void resize(int length) // 动态重置数组的长度
{
if( length != m_length )
{
update(copy(this->m_array, m_length, length), length);
}
}
~DynamicArray()
{
delete[] this->m_array;
}
};
}
#endif // DYNAMICARRAY_H
4.小结
- StaticArray 通过封装原生数组的方式实现数组类
- DynamicArray 动态申请堆空间,使得数组长度动态可变
- 数组对象能够代替原生数组,并且使用上更安全
- 代码优化是项目开发过程中不可或缺的环节