博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
六、数组类的创建
阅读量:5105 次
发布时间:2019-06-13

本文共 8060 字,大约阅读时间需要 26 分钟。

1、一些问题

顺序存储结构的线性表存在着两个方面的问题:

  1. 功能方面:数组操作符的重载,线性表有可能被误用为数组使用
  2. 效率方面:在一些场合中,效率上是有隐患的

解决方案:当前的库中没有可以代替原生数组的实现,所以有可能会被误用,需要创建一个数组类代替原生数组。

2、数组类抽象类模板的创建

1372866-20180816222725469-1527813736.png

需求分析:创建数组类代替原生数组的使用

  • 如何通过类的对象来模拟数组的行为?
  • 原生数组使用过程中存在的问题:
    • 数组类长度信息丢失:定义一个数组,长度信息必须指定,但是指定之后,长度信息不能在数组本身中找到,需要用另一个变量来保存
    • 数组越界问题:数组是一片连续的内存空间,但是原生数组发生越界时,不能立即发现,这是工程中bug来源之一,需求:数组类能主动发现越界访问

Array设计要点:

  • 抽象类模板,存储空间的位置和大小由子类完成
  • 重载数组操作符,判断访问下标是否合法
  • 提供数组长度的抽象访问函数
  • 提供数组对象间的复制操作(C++原生数组之间是不能直接通过赋值操作符进行相互复制)

Array类的声明

template
class Array : public Object{protected: T* m_array;public: virtual bool set(int i, const T& e); virtual bool get(int i, T& e) const; virtual int length() const = 0; // 数组访问操作符 T& operator[] (int i); T operator[] (int i) const;}
template 
class Array : public Object{protected: T* m_array;public: virtual bool set(int i, const T& e) { bool ret = ((i >= 0) && (i < length())); if (ret) { m_array[i] = e; } return ret; } virtual bool get(int i, T& e) { bool ret = ((i >= 0) && (i < length())); if (ret) { e = m_array[i]; } return ret; } virtual int length() const = 0; // 数组访问操作符 T& operator [] (int i) { if ((i >=0) && (i < length())) { return m_array[i]; } else { THROW_EXCEPTION(NoEnoughMemoryException, "Parameter i is invalid..."); } } T operator [](int i) const { return (const_cast
&>(*this)[i]); }};

3、StaticArray类模板创建

StaticArray设计要点:类模板

  • 封装原生组:父类只定义了操作,没有具体定义保存数据的地方,StaticArray中将数据保存在原生数组中,原生数组的表现形式就是StaticArray中的一个成员
  • 使用模板参数决定原生数组大小
  • 实现函数返回数组长度
  • 拷贝构造和赋值操作
template < typename T, int N >class StaticArray : public Array
{protected: T m_space[N];public: StaticArray(); // 拷贝构造和赋值操作 StaticArray(const StaticArray
& obj); StaticArray
& operator = (const StaticArray
& obj); int length() const;};
template < typename T, int N >class StaticArray : public Array
{protected: T m_space[N];public: StaticArray() { this->m_array = m_space; } // 拷贝构造和赋值操作 StaticArray(const StaticArray
& obj) { this->m_array = m_space; for(int i = 0; i < N; i++) { m_space[i] = obj.m_space[i]; } } StaticArray
& operator = (const StaticArray
& 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; }};

4、DynamicArray类模板创建

StaticArray的对象,数组的大小是明确指定的,创建动态数组类模板,数组大小可以动态指定

DynamicArray设计要点:类模板

  • 动态确定内部数组空间的大小
  • 实现函数返回数组长度
  • 拷贝构造和赋值操作

DynamicArray类的声明:

template < typename T >class DynamicArray : public Array
{public: int m_length;public: DynamicArray(int m_length); DynamicArray(const DynamicArray
& obj); DynamicArray
& operator = (const DynamicArray
& obj); int length() const; void resize(int length); // 动态重置数组的长度 ~DynamicArray();};
template < typename T >class DynamicArray : public Array
{public: 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 creat DynamicArray object..."); } } DynamicArray(const DynamicArray
& obj) { // 数组长度以参数对象的长度为准 this->m_array = new T[obj.m_length]; if (this->m_array != NULL) { cout << "DynamicArray(const DynamicArray
& obj)" << endl; // 长度设置 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 creat DynamicArray object..."); } } DynamicArray
& operator = (const DynamicArray
& 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 DynamicArray object..."); } } return *this; } 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 DynamicArray object..."); } } } ~DynamicArray() { delete[] this->m_array; }};

5、代码优化

分析构造函数、拷贝构造函数、赋值操作符重载函数和resize函数,程序逻辑为:

构造函数:

  • 堆空间中申请一片内存
  • 对数组类对象的成员变量进行赋值操作

拷贝构造函数:

  • 堆空间中申请一片内存
  • 进行数据元素的复制操作
  • 对成员变量进行赋值

赋值操作符重载函数:

  • 堆空间中申请一片内存
  • 进行数据元素的复制操作
  • 将指定的堆空间作为内部存储数组使用,更新成员变量的值

resize函数:

  • 堆空间中申请一片内存
  • 进行数据元素的复制操作,根据长度信息进行复制
  • 将指定的堆空间作为内部存储数组使用,更新类成员变量的值

总结:赋值操作符重载和resize代码中有很多重复的逻辑, 构造函数和拷贝构造函数也有很多重复代码,如何进行代码优化

重复代码逻辑的抽象

  • init:对象构造时的初始化操作,对成员变量进行初始化赋值
  • copy:在堆空间中申请新的内存,并执行拷贝复制操作
  • update:将指定的堆空间作为内部存储数组使用,更新成员变量的值
void init(T* array, int length){    if (array != NULL)    {        this->m_array = array;        this->m_length = length;    }    else    {        THROW_EXCEPTION(NoEnoughMemoryException, "No memory to init DynamicArray object...");    }}
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];        }     }     else     {         THROW_EXCEPTION(NoEnoughMemoryException, "No memory to copy DynamicArray object...");     }     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...");     }}

这三个函数均放在protected成员函数内

于是代码简化为:

public:    DynamicArray(int length)    {        init(new T[length], length);    }    DynamicArray(const DynamicArray
& obj) { init(copy(obj.m_array, obj.m_length, obj.m_length), obj.m_length); } DynamicArray
& operator = (const DynamicArray
& 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) // 动态重置数组的长度 { update(copy(this->m_array, this->m_length, length), length); } ~DynamicArray() { delete[] this->m_array; }

6、总结

StaticArray通过封装原生数组的方式实现数组类

DynamicArray动态申请堆空间,使得数组长度动态可变

数组对象能够代替原生数组,并且使用上更安全

代码优化是项目开发过程中不可或缺的环节

转载于:https://www.cnblogs.com/chenke1731/p/9490549.html

你可能感兴趣的文章
iframe跨域与session失效问题
查看>>
aboutMe
查看>>
【Debug】IAR在线调试时报错,Warning: Stack pointer is setup to incorrect alignmentStack,芯片使用STM32F103ZET6...
查看>>
一句话说清分布式锁,进程锁,线程锁
查看>>
Hash和Bloom Filter
查看>>
SQL Server获取月度列表
查看>>
python常用函数
查看>>
python 描点画圆
查看>>
FastDFS使用
查看>>
服务器解析请求的基本原理
查看>>
pycharm 如何设置方法调用字体颜色
查看>>
VUE源码解析心得
查看>>
[HDU3683 Gomoku]
查看>>
【工具相关】iOS-Reveal的使用
查看>>
整体二分——[Poi2011]Meteors
查看>>
数据库3
查看>>
delphi之事件
查看>>
windows server 2008 r2 安装
查看>>
存储分类
查看>>
下一代操作系统与软件
查看>>