创建StaticArray时,数组的大小必须是明确指定的,是一种限制。
全新的数组类:DynamicArray使用时其对象代表的数组的大小能够动态的指定
1、DynamicArray设计要点
- 类模板
- (任意时刻)动态确定内部数组空间大小 即存储数组的空间可以动态的指定
- 实现函数返回数组长度
- 拷贝构造和赋值操作
2、DynamicArray类的声明
3、DynamicArray实现
DynamicArray.h
1 #ifndef DYNAMICARRAY_H 2 #define DYNAMICARRAY_H 3 #include "array.h" 4 5 namespace DataStructureLib 6 { 7 template <typename T> 8 class DynamicArray:public Array<T> 9 { 10 protected: 11 int m_length; 12 public: 13 DynamicArray(int length) 14 { 15 m_array=new T[length]; 16 if(m_array!=NULL) 17 { 18 m_length=length; 19 } 20 else 21 { 22 THROW_EXCEPTION(NotEnoughMemoryException,"No Enough Memory to Create DynamicArray..."); 23 } 24 } 25 26 DynamicArray(const DynamicArray<T>& obj) 27 { 28 m_array=new T[obj.length()]; 29 if(m_array!=NULL) 30 { 31 32 for(int i=0;i<obj.length();i++) 33 { 34 this->m_array[i]=obj.m_array[i]; 35 } 36 m_length=obj.length(); 37 } 38 else 39 { 40 THROW_EXCEPTION(NotEnoughMemoryException,"No Enough Memory to Create DynamicArray..."); 41 } 42 } 43 44 DynamicArray& operator =(DynamicArray & obj) 45 { 46 //delete m_array []; 47 //这里不能先delete[] this->m_array,再 48 //赋值,因为delete可能会引起T调用析构函数,而如果在析构函数中抛出异常,以下对 49 //成员变量的赋值都将无法进行,从而造成函数异常时的不安全。因此,正确的顺序应该是 50 //先对成员变量赋值,最后再释放m_array的旧空间。 51 52 if(this!=&obj) 53 { 54 //1. 分配新内存 55 T* array=new T[obj.length()]; 56 //2. 拷贝数组的 57 for(int i=0;i<obj.length();i++) 58 { 59 array[i]=obj[i]; 60 } 61 //3. 设置变量 62 T* temp=this->m_array;//先设置参数,再删除m_array,以确保异常安全 63 64 this->m_length=obj.length(); 65 m_array=array; 66 67 delete []temp; 68 } 69 70 return *this; 71 } 72 73 int length() const 74 { 75 return m_length; 76 } 77 78 void resize(int length) 79 { 80 if(m_length!=length) 81 { 82 int size=(m_length<length)?m_length:length; 83 84 T* array=new T[size]; 85 86 if(array!=NULL) 87 { 88 for(int i=0;i<size;i++) 89 { 90 array[i]=m_array[i]; 91 } 92 93 T* temp=m_array; 94 95 m_array=array; 96 m_length=length; 97 98 delete []temp; 99 } 100 else 101 { 102 THROW_EXCEPTION(NotEnoughMemoryException, "Not enough memory to resize Object ...."); 103 } 104 105 106 } 107 } 108 109 ~DynamicArray() 110 { 111 delete []m_array; 112 } 113 }; 114 } 115 #endif // DYNAMICARRAY_H
main.cpp
1 #include <iostream> 2 #include "Exception.h" 3 #include "dynamicarray.h" 4 5 using namespace std; 6 using namespace DTLib; 7 8 int main() 9 { 10 DynamicArray<int> d(5); 11 12 for(int i=0;i<d.length();i++) 13 { 14 d[i]=i*i; 15 } 16 17 18 for(int i=0;i<d.length();i++) 19 { 20 cout<<d[i]<<endl; 21 } 22 23 d.resize(5); 24 25 for(int i=0;i<d.length();i++) 26 { 27 cout<<d[i]<<endl; 28 } 29 30 DynamicArray<int> d2(10); 31 32 d2=d; 33 34 for(int i=0;i<d2.length();i++) 35 { 36 cout<<d2[i]<<endl; 37 } 38 39 return 0; 40 }
3. DynamicArray类的问题与重构
(1)逻辑问题:
①函数实现存在重复的逻辑(如赋值与resize函数)
②从逻辑看,代码可分解出更细的功能(如分配新内存、数组拷贝、设置新变量等)
(2)代码优化
①init():对象构造时的初始化操作
②copy():在堆空间中申请新的内存,并执行拷贝操作
③update():将指定的堆空间设置为内部存储数组
【编程实验】动态数组类的实现与重构
#ifndef DYNAMICARRAY_H #define DYNAMICARRAY_H #include "array.h" namespace DataStructureLib { 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 updata(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(NotEnoughMemoryException, "Not enough memory to update DynamicArray Object ...."); } } //对象构造时的初始化操作 void init(T* array,int length) { m_array=array; if(m_array!=NULL) { m_length=length; } else { THROW_EXCEPTION(NotEnoughMemoryException,"No Enough Memory to Create DynamicArray..."); } } public: DynamicArray(int length) { // m_array=new T[length]; // if(m_array!=NULL) // { // m_length=length; // } // else // { // THROW_EXCEPTION(NotEnoughMemoryException,"No Enough Memory to Create DynamicArray..."); // } init(new T[length],length ); } DynamicArray(const DynamicArray<T>& obj) { ///////////////////// // m_array=new T[obj.length()]; // if(m_array!=NULL) // { // for(int i=0;i<obj.length();i++) // { // this->m_array[i]=obj.m_array[i]; // } // m_length=obj.length(); // } // else // { // THROW_EXCEPTION(NotEnoughMemoryException,"No Enough Memory to Create DynamicArray..."); // } T* array= copy(obj.m_array,obj.m_length,obj.m_length); init(array,obj.m_length); } DynamicArray& operator =(DynamicArray & obj) { //delete m_array []; //这里不能先delete[] this->m_array,再 //赋值,因为delete可能会引起T调用析构函数,而如果在析构函数中抛出异常,以下对 //成员变量的赋值都将无法进行,从而造成函数异常时的不安全。因此,正确的顺序应该是 //先对成员变量赋值,最后再释放m_array的旧空间。 if(this!=&obj) { //1. 分配新内存 // T* array=new T[obj.length()]; //2. 拷贝数组的 // for(int i=0;i<obj.length();i++) // { // array[i]=obj[i]; // } //3. 设置变量 // T* temp=this->m_array;//先设置参数,再删除m_array,以确保异常安全 // this->m_length=obj.length(); // m_array=array; // delete []temp; /***********重构后**************/ T* array=copy(obj,obj.length(),obj.length()); updata(array,obj.m_length); } return *this; } int length() const { return m_length; } void resize(int length) { if(m_length!=length) { // int size=(m_length<length)?m_length:length; // T* array=new T[size]; // if(array!=NULL) // { // for(int i=0;i<size;i++) // { // array[i]=m_array[i]; // } // T* temp=m_array; // m_array=array; // m_length=length; // delete []temp; // } // else // { // THROW_EXCEPTION(NotEnoughMemoryException, "Not enough memory to resize Object ...."); // } T* array= copy(this->m_array,this->m_length,length); updata(array,length); } } ~DynamicArray() { delete []m_array; } }; } #endif // DYNAMICARRAY_H