C++编程练习1:动态数组(Dynamic Array)类的封装练习 下载本文

内容发布更新时间 : 2024/5/17 19:05:13星期一 下面是文章的全部内容请认真阅读。

C++编程练习1:动态数组(Dynamic Array)类的封装练习

程序环境

学习使用Visual C++ 6.0环境开始编程:学习最简单的使用Win32 Console Project (类似于Turbo C中的环境),使用说明可见:

http://www.math.zju.edu.cn/ligangliu/Courses/DataStructure_2005-2006/SourceCodes/C2C++/NewConsole.htm

编程规范

编写程序一定要养成良好的代码习惯。“程序不是写给自己看的,是写给别人看的”。 学习规范化编程,养成良好的习惯。可参考编程规范及技巧的文档: http://www.math.zju.edu.cn/ligangliu/ForStudents/C++/CodingSkills.rar

http://www.math.zju.edu.cn/ligangliu/_download/Training/Documents/Talks/Coding/CodingBasicSkills.rar

注意:不同的团体、公司都有各自的编程规范,没有统一的编程规范。在编程训练的初期,只要选择自己喜欢的一套比较统一的编程规范来写即可,不必追求与上述文档完全一致的编程规范。以后随着编程水平的提高以及查看其他规范的代码后,可根据自己的喜好和合作团队的要求来不断调整自己的编程规范。

动态数组类的演示过程

使用固定大小的数组,如 double a[100];

有使用不方便的地方:数组大小固定,不灵活;如果程序使用的情况数组元素的个数多于100,则要改数组大小,然后重新编译程序;如果程序使用的情况数组元素的个数很少,则有大量的空间被浪费。

为了解决这个矛盾,可以使用动态分配内存空间的方法(需要对内存的动态分配的机制和原理了解和熟悉),即,

采用一个指针p记录数组的头地址;采用一个整数n记录数据元素的个数

程序运行时,用多少个元素n,就从内存中申请多少空间来存储数组p;p所指向的内存空间的数组元素总是n。n一旦变化,p即申请新的空间用来存储数组(当然需释放掉以前的内存空间,以免造成内存泄漏)。这样,对数组的操作是通过一些函数来操作:这些函数就是对操作这个数组的“接口”。 上述的程序大概形式可见:

http://www.math.zju.edu.cn/ligangliu/Courses/DataStructure_2005-2006/SourceCodes/C2C++/Array0.rar

由于p 和 n之间有强烈的逻辑关系,自然可以用struct将它们“包”在一起处理,见:

http://www.math.zju.edu.cn/ligangliu/Courses/DataStructure_2005-2006/SourceCodes/C2C++/Array1.0.rar http://www.math.zju.edu.cn/ligangliu/Courses/DataStructure_2005-2006/SourceCodes/C2C++/Array1.1.rar

这时发现那些操作数组的接口函数,都是操作struct的数据,自然可以想到将这些函数“放”到struct里面。在struct中放函数在C中是不行的,但是在C++中是可以的。这样大概如下形式:

http://www.math.zju.edu.cn/ligangliu/Courses/DataStructure_2005-2006/SourceCodes/C2C++/Array2.rar

此时发现,数据p,n及处理它们的函数都“包”在一起,放在一个struct中,这就是对它们的一种封装。用户只要操作这个struct的函数,就可以操作一个“数组”。

我们将关键词struct改为class,然后将函数的类型改为public,其他不变,这个程序就可以编译运行。这事实上就是一个简单的C++的程序,并且大致完成了一个class!见:

http://www.math.zju.edu.cn/ligangliu/Courses/DataStructure_2005-2006/SourceCodes/C2C++/Array3.rar

在写C++程序时,一般一个类需要2个文件,一个头文件*.h(定义了这个类的接口),一个实现文件*.cpp(具体这个类的实现),见:

http://www.math.zju.edu.cn/ligangliu/Courses/DataStructure_2005-2006/SourceCodes/C2C++/Array4.rar

希望上述过程好好体会一下。注意:上述的代码都不太符合编程规范,只是演示了大致的一个过程。你需按照严格的编程规范来完成该练习。

作业及要求

现在要求动态数组的类的接口如下: class DArray {

private: double *m_pData; // 存放数组的动态内存指针 int m_nSize; // 数组的元素个数

private: void Init(); // 初始化 void Free(); // 释放动态内存 inline int InvalidateIndex(int nIndex); // 判断下标的合法性

public: DArray(); // 缺省构造函数 DArray(int nSize, double dValue = 0); // 其他构造函数,设置一定数组大小,并设置所有元素为0;当然还可以定义其他不同参数的构造函数,以方便用户使用 DArray(const DArray& arr); // 拷贝构造函数(最好为所有包含动态分配成员的类都提供拷贝构造函数) ~DArray(); // 析构函数 void Print(); // 输出显示所有数组元素的值 int GetSize(); // 获取数组大小(元素个数)

int SetSize(int nSize); // 重新设置数组的大小。注:若nSize小于原数组大小,可截断取前nSize个元素作为新数组的元素;若nSize大于原数组大小,新增的元素的值设置缺省值0即可 double GetAt(int nIndex); // 获取某个元素

double operator[] (int nIndex) const; // 重载[]操作符,以便像传统数组那样通过a[k]来获取元素值 int SetAt(int nIndex, double dValue); // 设置某个元素的值 int PushBack(double dValue); // 追加一个新的元素到数组末尾 int DeleteAt(int nIndex); // 从数组中删除一个元素 int InsertAt(int nIndex, double dValue); // 插入一个新的元素到数组中 CDArray &CDArray::operator = (const CDArray& array); // 重载赋值操作符号\};

其他:

#define SAFEDELETE(p) if(p) {delete p; p=NULL;} #define SAFEDELETES(p) if(p) {delete [] p; p=NULL;}

测试代码: void main() {

void main() { DArray a; a.InsertAt(0, 2.1); a.Print(); a.PushBack(3.0); a.PushBack(3.1); a.PushBack(3.2); a.Print(); a.DeleteAt(0); a.Print(); a.InsertAt(0, 4.1); a.Print(); DArray acopy = a; //此处用到了拷贝构造函数 acopy.Print(); a.DeleteAt(0); //测试是否正确写了拷贝构造函数 a.Print(); acopy.Print();