您的当前位置:首页正文

面向对象程序设计报告 Drawcli

来源:九壹网


面向对象程序设计报告

——关于Drawcli的程序分析

一、 程序分析

1. 程序简介

Drawcli是一个微软MSDN中附带的一个示例程序,能够进行简单的绘图操作,主要包括16个.cpp文件,而每个.cpp文件都对应了一个.h文件。

2. 界面分析

在drawcli文件夹中有drawcli.exe可执行程序,点击后进入主程序界面,它包含了一般Windows程序通有的一些结构。最上方是标题栏,再往下是菜单栏,翻译成中文,有文件、编辑、查看、绘画、对象、窗口、帮助七个下拉菜单,往下便是工具栏,包括新建、打开、保存、剪切、复制、粘贴、箭头、画图工具、打印、关于、帮助按钮,然后便是图形编辑界面,它是一个独立的窗口,已经给出了等间距的虚线,可以新建、打开、关闭等,以上就是打开drawcli.exe程序后大概的界面。

3. 功能分析

该程序是一个简易的绘图程序,新建绘图页面后,可以在菜单栏中“Draw”的下拉菜单或者工具栏中的绘图工具按钮中选择需要的图形,分别有直线、矩形、圆角矩形、椭圆、点画多边形等画图模式,在编辑区通过鼠标的点击可以画出相应图形,并且可以实现拖动功能。在菜单栏中“Object”下拉菜单中选择对应功能,可以实现自定义线宽、填充颜色、图层移动等功能。同时,在绘图的同时,也可以通过右键点击、工具栏按钮或者快捷键对图形进行复制、剪切、粘贴的操作。在绘图完成之后,用“Save”按钮或者“File”下拉菜单中的“Save”进行用户自定义路径的保存,保存默认格式为.drw。程序中的“About”和“Help”提供了程序的一些版本信息。

二、 源代码分析

1. 常量

在整个程序中,在很多地方定义了常量,例如形如const CRect & rect的常量

引用的定义,形如void AssertValid() const的常量函数的定义,其中引用变量的使用,主要出现在函数自检传值时,形参的定义,帮助实现了函数自检的地址传输,有利于数据在函数与函数之间的传递。程序中同样存在new运算符,即动态分配存储空间的使用,如CDrawObj* pClone = new CDrawObj(m_position)语句中即通过new申请了一块CDrawObj类大小的内存空间给与CDrawObj指针,与此相对的,运用了delete运算符将所申请的内存空间释放掉。对于作用域运算符::的使用,主要是在对类中已经申明的函数在类外进行定义时用到,如CDrawDoc类中声明的构造函数CDrawDoc()在另一个头文件中进行定义,其定义形式为CDrawDoc::CDrawDoc(),用以指明CDrawDoc()函数的存在区域。

2. 类

作为面向对象程序,其中含有大量的class类的定义,主要有四个绘图对象类,其中各类的主要说明如下:

2.1 class CDrawObj

其中CdrawObj是父类,不作为具体的绘图类对象存在。

class CDrawObj : public CObject { protected: DECLARE_SERIAL(CDrawObj); CDrawObj(); // Constructors public: CDrawObj(const CRect& position); // Attributes CRect m_position;//对象显示的位置 CDrawDoc* m_pDocument;//对象存储对应的文档对象指针 virtual int GetHandleCount();//获得对象特征点数量 virtual CPoint GetHandle(int nHandle);//获得对象特针点的位置 CRect GetHandleRect(int nHandleID, CDrawView* pView);//获得特征点的小矩形 virtual HCURSOR GetHandleCursor(int nHandle);//获得特征点的鼠标形状 virtual void SetLineColor(COLORREF color);//设置线条颜色 virtual void SetFillColor(COLORREF color);//设置填充颜色 // Operations

virtual void Draw(CDC* pDC);//纯虚函数,由子对象自己实现 enum TrackerState { normal, selected, active };//对象的状态(一般、被选、活动) virtual void DrawTracker(CDC* pDC, TrackerState state);//绘出特征点 virtual void MoveTo(const CRect& positon, CDrawView* pView = NULL);//移动到一个新的位置,要求重绘 virtual int HitTest(CPoint point, CDrawView* pView, BOOL bSelected);//如果对象被选择,返回特征点;如果没有被选择,返回是否在对象内 virtual BOOL Intersects(const CRect& rect);//判断对象和矩形是否重叠 virtual void MoveHandleTo(int nHandle, CPoint point, CDrawView* pView = NULL);//通过特征点的移动来改变形状大小 virtual void OnOpen(CDrawView* pView);//调用OnEditProperties()来修改属性 virtual void OnEditProperties();//打开修改属性对话框,修改属性 virtual CDrawObj* Clone(CDrawDoc* pDoc = NULL);//创建一个新的CDrawObj对象,并加入到pDoc中 virtual void Remove();//delete自己 void Invalidate();//对应的m_pDocument对象更新所有视图 // Implementation public: virtual ~CDrawObj(); virtual void Serialize(CArchive& ar);//保存数据、读取数据 #ifdef _DEBUG void AssertValid(); #endif // implementation data protected: BOOL m_bPen;//是否使用笔 LOGPEN m_logpen;//笔的属性 BOOL m_bBrush;//是否使用刷子 LOGBRUSH m_logbrush;//刷子属性 }; 2.2 CdrawRect

在CdrawObj中已经实现了许多功能,因此在CdrawRect中只是实现了需要修改和增加的函数。

class CDrawRect : public CDrawObj { protected: DECLARE_SERIAL(CDrawRect); CDrawRect(); public:

CDrawRect(const CRect& position);//添加了对新数据成员的初始化 // Implementation public: virtual void Serialize(CArchive& ar);//添加了对新数据成员操作 virtual void Draw(CDC* pDC);//根据要求画出每个图形 virtual int GetHandleCount();//line和roundRectangle特殊处理 virtual CPoint GetHandle(int nHandle);//line和roundRectangle特殊处理 virtual HCURSOR GetHandleCursor(int nHandle);//line和roundRectangle特殊处理 virtual void MoveHandleTo(int nHandle, CPoint point, CDrawView* pView = NULL);//通过特征点来修改大小 virtual BOOL Intersects(const CRect& rect);//判断与图形是否存在相交 virtual CDrawObj* Clone(CDrawDoc* pDoc);//Clone一个新对象加入到pDoc中 protected: enum Shape { rectangle, roundRectangle, ellipse, line }; Shape m_nShape;//通过枚举变量来标示属于上述四种的哪一种形状 CPoint m_roundness; // for roundRect corners friend class CRectTool; }; 2.2 CDrawPoly

class CDrawPoly; class CDrawPoly : public CDrawObj { protected: DECLARE_SERIAL(CDrawPoly); CDrawPoly(); public: CDrawPoly(const CRect& position); // Operations void AddPoint(const CPoint& point, CDrawView* pView = NULL);//增加新的点 BOOL RecalcBounds(CDrawView* pView = NULL);//计算这些点的外围大小 // Implementation public: virtual ~CDrawPoly(); virtual void Serialize(CArchive& ar); virtual void Draw(CDC* pDC); virtual void MoveTo(const CRect& position, CDrawView* pView = NULL);

virtual int GetHandleCount(); virtual CPoint GetHandle(int nHandle); virtual HCURSOR GetHandleCursor(int nHandle); virtual void MoveHandleTo(int nHandle, CPoint point, CDrawView* pView = NULL); virtual BOOL Intersects(const CRect& rect); virtual CDrawObj* Clone(CDrawDoc* pDoc); protected: int m_nPoints; int m_nAllocPoints; CPoint* m_points; CDrawPoly* m_pDrawObj; friend class CPolyTool; }; 2.3 CDrawOleObj

class CDrawOleObj : public CDrawObj { protected: DECLARE_SERIAL(CDrawOleObj); CDrawOleObj(); public: CDrawOleObj(const CRect& position); // Implementation public: virtual void Serialize(CArchive& ar); virtual void Draw(CDC* pDC); virtual CDrawObj* Clone(CDrawDoc* pDoc); virtual void OnOpen(CDrawView* pView); virtual void MoveTo(const CRect& positon, CDrawView* pView = NULL); virtual void OnEditProperties(); virtual void Remove(); virtual ~CDrawOleObj(); static BOOL c_bShowItems; CDrawItem* m_pClientItem; CSize m_extent; // current extent is tracked separate from scaled position }; 另外存在29处自定义的新类,并且所有的类的定义均在头文件中完成。大

部分的类的定义中都用到了两种或以上的访问限制符,如CDrawDoc类中用到了public和protect两种访问限制符。每个类中大都定义了一定数量的构造函数,包含各种类型的构造函数。如类CProperty中含有CProperty( void )函数和CProperty( DWORD dwID, const LPVOID pValue, DWORD dwType )函数,类CRectDlg中含有的构造函数CRectDlg(CWnd* pParent = NULL),其中前者是无参构造函数,后者则为一般构造函数,第三个构造函数则为复制构造函数。与构造函数相对的,类中必然定义了与此对应的析构函数,用于撤销该类,如class CDrawView中的函数virtual ~CDrawView()则为其对应的析构函数。类中还含有大量的一般成员函数,主要执行访问本类数据成员以及完成本类主要功能的任务。如CDrawView类中的void Select(CDrawObj* pObj, BOOL bAdd = FALSE),CDrawDoc类中的CDrawObjList* GetObjects()等函数即是一般成员函数。其中CDrawObjList* GetObjects()函数的主要功能为返回一个地址值。关于this指针的运用,程序中主要将其进行隐式调用,一般在运算符重载,调用成员函数时用到。C++中的静态成员在此程序中亦有用到,如类CDrawOleObj中的static BOOL c_bShowItems;即为静态数据成员。为了在程序中建立类与类之间联系,提高程序执行效率,降低程序中消息在类与类之间传递而带来的开销,各个代码中也包括友元函数和友元类,如类COleDataSource中的friend class COleServerItem,即为友元类。

3. 继承

这个程序中也运用了大量类的继承。类的继承已成为这个程序的主体部分。在此程序的类的继承中,大多数的继承为public继承方式,即公有继承方式,如类AFX_NOVTABLE COleServerItem的定义则公有继承了类CDocItem,相应的,类的private继承和protect继承在此程序中较少运用。在定义完派生类后,按照一般的类的规则,需要编写对类中数据成员初始化的构造函数和撤销类时释放内存的析构函数,如类CDrawPoly中就含有函数CDrawPoly()作为其构造函数,同时有virtual ~CDrawPoly()虚析构函数作为此类的析构函数。类CDrawOleObj中也含有函数CDrawOleObj()作为其构造函数,相应的virtual ~CDrawOleObj()作为其析构函数。派生类中的构造函数以及析构函数的类型与定义和运用的方式大致与基类中的构造函数和析构函数相似,不同之处主要在于构造函数中的初始化列表中的参数必须包括基类的初始化的参数。派生类中的一般成员函数定义也与基类中相

同,初始化方式中亦可以定义默认值或在函数调用时运用实参给形参赋值的方式。对于C++中允许的多继承在此程序运用则较少,大都是单继承的形式呈现在程序中。

4. 多态性

在这个程序中也有很多地方体现出面向对象程序设计的对态性的特点。首先,在程序中运用到了运算符重载的形式,如类COleDataObject中的

operator=(const COleDataObject&)语句,即实现了“=”符号的重载,此形式为重载运算符函数;又如类CString中的friend CString AFXAPI operator+…语句中,同样是把“+” 符号进行了重载,不同的是上面是将符号重载为运算符函数,而后面则是把符号重载成为友元函数,此两种形式有其各自的特点:重载成运算符函数时,由于有this指针的存在,参数的个数为运算符的目数少一,而重载成为友元函数时,由于友元函数不含this指针,参数表中的参数的数量与所重载的运算符的目数相同;这两种重载方式对与不同运算符有着各自选择,如单目运算符最好选用成员函数的重载方式,而双目运算符最好重载成为友元函数,如此程序中的“+”符号作为双目运算符,都重载成友元函数。关于虚函数,在此程序中有很多地方用到,虚函数的运用,主要是为了动态联编,如类CMainFrame中存在三个虚函数:virtual ~CMainFrame(),virtual void AssertValid() const,virtual void Dump(CDumpContext& dc) const,其中还含有一个虚析构函数。

三、 总结

以上便是对程序本身以及源代码的分析,它运用面向对象的思想,涵盖了C++的大部分知识。而在分析这个程序的过程中,我们也更加巩固了所学的关于C++的各种知识,同时,我们也逐渐熟悉了这种专业而又规范的C++程序编写的格式,对于指导我们以后的编程习惯有着莫大的帮助,相信以后随着对此类程序更深入的研究,我们自己也一定会编出同样精彩的程序。

因篇幅问题不能全部显示,请点此查看更多更全内容