1、数组类的创建
目标:完成Array,StaticArray,DynamicArray类的具体实现
需求分析:创建数组类代替原生数组的使用
- 数组类包含长度信息,能够主动发现越界访问
Array设计要点
-抽象类模板,存储空间的位置和大小由子类完成
-重载数组操作符,判断访问下标是否合法
-提供数组长度的抽象访问函数
-提供数组对象间的复制操作
2、编程实验
数组抽象类实现 Array.h
#ifndef ARRAY_H
#define ARRAY_H
#include "Object.h"
#include "Exception.h"
namespace DTLib
{
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(IndexOutOfBoundsExpception, "Parameter i is invalid ...");
}
}
T operator[] (int i) const
{
return const_cast<T&>(*this)[i];
}
T* array() const
{
return m_array;
}
virtual int length() const = 0;
};
}
#endif // ARRAY_H
3、StaticArray
StaticArray设计要点
- 封装原生数组
- 使用模板参数决定数组大小
- 实现函数返回数组长度
- 拷贝构造和赋值操作
4、编程实验
静态数组类的实现 StaticArray.h
#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>& e)
{
this->m_array = m_space;
for(int i = 0; i < N; i++)
{
this->m_array[i] = m_space[i];
}
}
StaticArray<T, N>& operator= (const StaticArray<T, N>& obj)
{
if(this != &obj)
{
for(int i = 0; i < N; i++)
{
this->m_array[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 DTLib;
int main()
{
StaticArray<int, 5> s1;//创建容量为5静态数组存放int数据
for(int i = 0; i < s1.length(); i++)
{
s1[i] = i * i;
}
for(int i = 0; i < s1.length(); i++)
{
cout << s1[i] << endl;
}
StaticArray<int, 5> s2;//再创建一个容量为5的数组存放int数据
s2 = s1;//调用重载的赋值操作符重载函数,将s1的值拷贝到s2
for(int i = 0; i < s2.length(); i++)
{
cout << s2[i] << endl;
}
//看看原生数组的弊端
int s3[2];
s3[4] = 100;//难以调试
s3[6] = 100;//越界访问,编译居然不报错
s2[6] = 10;//抛异常
return 0;
}
5、DynamicArray
DynamicArray设计要点
★ 动态确定内部数组空间的大小
★ 实现函数返回数组长度
★ 拷贝构造和赋值操作
6、编程实验
动态数组的实现 DynamicArray.h
#ifndef DYNAMICARRAY_H
#define DYNAMICARRAY_H
#include "Array.h"
#include "Exception.h"
namespace DTLib
{
template <typename T>
class DynamicArray : public Array<T>
{
protected:
int m_length;
public:
DynamicArray(int length = 0)
{
this->m_array = new T[length];
if( this->m_array != 0 )
{
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 != 0 )
{
this->m_length = obj.m_length;
for(int i = 0; i < 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 != 0)
{
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 ...");
}
}
return *this;
}
int length() const
{
return m_length;
}
void resize(int length)
{
if(length != m_length)
{
T* array = new T[length];
if(array != 0)
{
int size = m_length < length ? m_length : 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 DTLib;
int main()
{
DynamicArray<int> s1(5);//创建容量为5的存放int数据的数组
for(int i = 0; i < s1.length(); i++)
{
s1[i] = i * i;
}
for(int i = 0; i < s1.length(); i++)
{
cout << s1[i] << endl;
}
DynamicArray<int> s2(10);
s2 = s1;
s2.resize(3);
for(int i = 0; i < s2.length(); i++)
{
cout << s2[i] << endl;
}
return 0;
}
DynamicArray类中的函数实现存在重复的逻辑,如何进行代码优化?
7、DynamicArray的优化
重复代码逻辑的抽象
- init() :对象构造时的初始化操作
- copy():在堆空间中申请新的内存,并执行拷贝操作
- update():将指定的堆空间作为内部存储数组使用
8、编程实验
动态数组的优化 DynamicArray.h
#ifndef DYNAMICARRAY_H
#define DYNAMICARRAY_H
#include "Array.h"
#include "Exception.h"
namespace DTLib
{
template <typename T>
class DynamicArray : public Array<T>
{
protected:
int m_length;
//初始化构造函数
void init(T* array, int length)
{
this->m_array = array;
if(this->m_array != 0)
{
m_length = length;
}
else
{
THROW_EXCEPTION(NoEnoughMemoryException, "No memory to create DynamicArray object ...");
}
}
//在堆空间中申请新的内存,并执行拷贝操作
T* copy(T* array, int len, int newlen)
{
T* ret = new T[newlen];
if( ret )
{
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 != 0 )
{
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 ...");
}
}
public:
DynamicArray(int length = 0)
{
init(new T[length], length);
}
DynamicArray(const DynamicArray<T>& obj)
{
//T* array = copy(obj.m_array, obj.m_length, obj.m_length);
//init(array, obj.m_length);
init(copy(obj.m_array, obj.m_length, obj.m_length), obj.m_length);
}
DynamicArray<T>& operator= (const DynamicArray<T>& obj)
{
if(this != &obj)
{
//T* array = copy(obj.m_length, obj.m_length, obj.m_length);
//update(array, obj.m_length);
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)
{
//T* array = copy(this->m_array, m_length, length);
//update(array, length);
update(copy(this->m_array, m_length, length), length);
}
}
~DynamicArray()
{
delete[] this->m_array;
}
};
}
#endif // DYNAMICARRAY_H
9、多维数组
DTLib是否有必要增加多维数组类?
多维数组的本质:数组的数组!
main.cpp
#include <iostream>
#include "DynamicArray.h"
using namespace std;
using namespace DTLib;
int main()
{
DynamicArray< DynamicArray<int> > d;//定义一个数组,数组中的每个元素又是一个数组对象(存放int数据)
d.resize(3);//数组的容量为3,存放数组类型数据(二维数组有3行)
for(int i = 0; i < d.length(); i++)
{
d[i].resize(i + 1); //每一个数据元素(为数组对象)的大小(每一行i+1个元素)
}
for(int i = 0; i < d.length(); i++)
{
for(int j = 0; j < d[i].length(); j++)
{
d[i][j] = i + j;
}
}
for(int i = 0; i < d.length(); i++)
{
for(int j = 0; j < d[i].length(); j++)
{
cout << d[i][j] << " ";
}
cout << endl;
}
return 0;
}
10、小结
StaticArray通过封装原生数组的方式实现数组类
DynamicArray动态申请堆空间,使得数组长度动态可变
数组对象能够代替原生数组,并且使用上更安全
代码优化是项目开发过程中不可或缺的环节