怎样实现图形多态序列化和显示

糊糊 2005-05-06 04:06:22
怎样实现图形多态显示?
比如说我有一个基类shape,它有两个虚函数draw()和move()功能,后来又从shape派生出来很多的其他的的基本图形类,比如说square,circle,ellipse等等,每一个类都重写了draw()和move(),我最终的目的是要在MFC程序的文档中存储绘制的图形列表,然后在视图中遍历图形列表,并显示出来,我应该怎么做?

我所知道的就是,多态的显示可以这么做
//图形拖放
void dragAndDrop(shape& s) throw()//<-----一个多态函数
{
s.move(42,24);//<------动态绑定调用"合适的代码",绑定合适的派生图形
s.draw();//<只要是从shape派生来的类,都可以调用,就像可以预测未来一样
}

当然了,这样简单的例子还行,一旦结合文档就麻烦了,为了记录每一个绘制的图形的数据,有必要建立一个列表.然后在视图中绘制的时候,遍历图形列表,使用图形多态显示.
多态的简单例子,可以参看 http://community.csdn.net/Expert/TopicView1.asp?id=3984730 中的部分内容.

显示到还好说,基于前面的多态应用的例子就可以了,关键是在文档中存储每一种图形数据的时候,很麻烦.


你可以想象,每一个派生的基本图形需要记录的数据是不一样的(这个和它所拥有的成员变量有关),怎么样在DOC中记录这个图形列表也是一个难事,既然C++支持多态,我想的就是用多态的功能来实现,却不知道具体怎么实现多态序列化,又怎么在视图中调用多态显示.

// shape.h: interface for the shape class.
//
//////////////////////////////////////////////////////////////////////

#if !defined(AFX_SHAPE_H__79AFD738_5912_4037_91F0_32F03E4EBEDB__INCLUDED_)
#define AFX_SHAPE_H__79AFD738_5912_4037_91F0_32F03E4EBEDB__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

class shape
{
public:
shape(int x,int y) throw();
shape(const shape& s) throw();
virtual ~shape() throw();
virtual void draw()const throw()=0;
virtual void move(int x,int y) throw()=0;
protected:
int x_,y_;
void operator =(const shape& s) throw();

};

=============================================
继承类,依稀记得代码来自C++ primier
class square : public shape
{
public:
virtual void move(int x,int y) throw();
virtual void draw() const throw();
square(int x,int y,int width) throw();
virtual ~square();
protected:
int width_;

};


class circle : public shape
{
public:
virtual void move(int x,int y) throw();
virtual void draw() const throw();
circle(int x,int y,int radius);
virtual ~circle();

protected:
int radius_;
};

#endif // !defined(AFX_SHAPE_H__79AFD738_5912_4037_91F0_32F03E4EBEDB__INCLUDED_)

/////////////很多代码就不列在这里了

以前看过别人写的EastDraw,VCKBase有的下载,没有看过的人先去
http://www.vckbase.com/code/viewcode.asp?id=1627 下载一个回来自己看看先.

作者实现的方法我感觉很笨拙,虽然管理起来也很方便,添加新的图形类也很方便,但是文档记录和图形显示没有利用多态性,使用了很多switch,添加了一个图形类,就要改动很多地方.

他的代码这里分析一下:
基类CUnit,派生于CObject,实现了添加了Serialize支持,和自绘制(当然,都是虚函数)
派生类:
CDLine,CCurve,CRectangle,CRoundRectangle,CEllipse,CRound,CPolygon,CLiEllipse,CRoundArc,CEllipseArc,CPolyBezier,CText,都有自己的Serialize,和自己重新实现DrawXXX()函数

这些都无可厚非,如果是我,我也会这么做的.
问题的关键在后面,看看他是怎么实现图形数据的记录和保存的:

1,文档数据成员,使用了一个很长的,各种图形类的列表,如下
class CEastDrawDoc : public CDocument
{
protected: // create from serialization only
CEastDrawDoc();
DECLARE_DYNCREATE(CEastDrawDoc)

// Attributes
public:
CObArray m_DLineArray;
CObArray m_CurveArray;
CObArray m_RectangleArray;
CObArray m_RoundRectangleArray;
CObArray m_EllipseArray;
CObArray m_RoundArray;
CObArray m_PolygonArray;
CObArray m_LiEllipseArray;
CObArray m_RoundArcArray;
CObArray m_EllipseArcArray;
CObArray m_PolyBezierArray;
CObArray m_TextArray;
省略......
}
2.序列化了,由上面的数据成员的定义,可以知道他只有下面的路走了:

我下载的源代码中,没有序列化的代码,但是我猜想肯定是这样的:
void CEastDrawDoc::Serialize(CArchive& ar)
{
if (ar.IsStoring())
{
// TODO: add storing code here
}
else
{
// TODO: add loading code here
}
//////我添加的
m_DLineArray.Serialize(ar);
m_CurveArray.Serialize(ar);
m_RectangleArray.Serialize(ar);
省略......
}
3.CEastDrawView::OnDraw(),代码中也没有实现,但是我想肯定是这样的:

void CEastDrawView::OnDraw(CDC* pDC)
{
CEastDrawDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
///我添加的
// 一个循环
pDoc->m_DLineArray[i].DrawXXX(CDC*...);
pDoc->m_CurveArray[i].DrawXXX(CDC*...);
pDoc->m_RectangleArray[i].DrawXXX(CDC*...);
省略......
}

诸位看官,看到这里你是否觉得作者这样的做法是否很好呢?我是不以为好的,但是不会说他差,只是觉得还有改进的地方.怎么改进,我这里也是和大家一起探讨,来实现图形的多态显示.

所以就希望高人出来解决了!!解决只需要点拨关键的地方就可以了.

我的做法是(全当作是抛砖引玉了):
文档数据存储
1.数据成员
// Attributes
public:
CTypedPtrList <CObList,CUnit *> m_UnitList;

2.序列化
void CEastDrawDoc::Serialize(CArchive& ar)
{
if (ar.IsStoring())
{
// TODO: add storing code here
}
else
{
// TODO: add loading code here
}
//保存图形列表
m_UnitList.Serialize(ar);
}
图形显示
3.视图显示
void CEastDrawView::OnDraw(CDC* pDC)
{
CEastDrawDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
///我添加的
// 一个循环
pDoc->m_UnitList[i].DrawXXX(CDC*...);
}

/////////////////////////////////////
但是我不知道这里会不会有问题出现,首先是序列化,我不能够肯定它能否实现图形多态序列化(自动调用派生类的Serialize()函数),然后是视图显示,我也不能够保证它能否实现图形多态显示(自动调用派生类的DrawXXX()函数).

到此,我的问题我才觉得讲清楚了,到底应该怎样实现图形多态序列化和图形多态显示,大侠们,显显身手吧!!!!!!!!!!!!!!
强烈召唤你们!!!!
...全文
250 4 打赏 收藏 转发到动态 举报
写回复
用AI写文章
4 条回复
切换为时间正序
请发表友善的回复…
发表回复
糊糊 2005-05-10
  • 打赏
  • 举报
回复
我还是自己顶吧,前天给侯捷发了个邮件,想让他来看看,人家是大忙人,就不等他来给我解决了。。。
糊糊 2005-05-09
  • 打赏
  • 举报
回复
楼上的,你说的很有道理,我也是想在保存的说话添加一个对象唯一标志的,只是没有想到读取的时候要动态创建对象完成读取;同时也没有搞过什么Manager之类的C++类,你有过这个方面的经验吗?
星辰游侠 2005-05-07
  • 打赏
  • 举报
回复
VCKBase的程序看了,不能说好。
我觉得还是增加一个中间的类比如CShapeManager,用来管理,序列化你的图形对象链表为好。
关于多态,深入浅出MFC中关于虚函数的章节有清晰的解释和用法
你的用法,m_UnitList.Serialize(ar);序列化可能没有问题,但是读出来就有问题了。
解决方法是在每次序列化一个对象前写入图形的标识,读取的时候由CShapsManager根据读出的标识,动态创建对象,再把ar传给这个对象完成读取。

victor_sun 2005-05-07
  • 打赏
  • 举报
回复
从头开始学吗
面向对象编程中,Shape类作为图形系统的基类设计,是理解继承、多态和抽象类的最佳实践案例。本文将从基础实现到高级应用,全面解析Shape类的设计模式及其在实际开发中的价值。 --- Shape类基础设计 1.1 抽象类与接口的选择 在面向对象设计中,抽象类和接口各有适用场景: 抽象类优势: 可以包含具体方法和抽象方法 能够定义成员变量 适合表示"is-a"关系 接口适用场景: 需要多重继承时 定义行为契约 轻量级规范 对于Shape类,抽象类是更合适的选择: 1.2 核心方法定义规范 必须实现的方法: calculateArea(): 计算图形面积 calculatePerimeter(): 计算图形周长 可选方法: draw(): 绘制图形 rotate(degree): 旋转图形 1.3 类关系设计 Shape类UML关系图: --- 具体图形实现 2.1 二维图形实现 2.1.1 圆形(Circle) 2.1.2 矩形(Rectangle) 2.2 三维图形扩展 2.2.1 球体(Sphere) --- 设计模式应用 3.1 工厂模式创建图形 3.2 装饰器模式增强功能 --- 高级应用场景 4.1 图形系统扩展 新增图形类型的步骤: 创建新类继承Shape 实现所有抽象方法 添加工厂支持(可选) 4.2 性能优化策略 --- 总结 设计原则: 开闭原则:通过继承扩展系统 里氏替换:子类可替换父类 单一职责:每个类只负责一种图形 实际应用建议: 优先使用组合而非继承 考虑使用Builder模式创建复杂图形 对频繁使用的图形实现缓存机制 扩展方向: 添加图形变换功能 实现序列化接口 支持图形组合(Composite模式)
内容概要:本文深入讲解C++继承机制中的虚函数与多态核心技术,涵盖虚函数的定义、实现原理(虚函数表vtable与vptr)、重写规则及注意事项,重点阐述多态的三大实现条件——继承、虚函数重写和基类指针/引用调用,并结合纯虚函数与抽象类的设计理念,展示其在构建可扩展软件架构中的关键作用。文章通过图形绘制、游戏角色控制、设备驱动等多个典型应用场景实例,系统性地演示了多态在提升代码灵活性、扩展性和可维护性方面的优势,最后以一个完整的图形编辑工具实战项目收尾,综合运用抽象类、多态、工厂模式与管理器模式,实现图形的添加、删除、绘制、面积计算等核心功能,全面展现面向对象设计思想在工程实践中的落地方式。 适合人群:具备C++基础语法知识,熟悉类与对象、继承机制,有一定编程经验(1-3年)的开发者,尤其适合希望深入理解面向对象高级特性及设计模式应用的程序员。 使用场景及目标:①掌握虚函数底层机制与多态实现原理;②理解抽象类与纯虚函数在接口设计中的作用;③学习如何在真实项目中应用多态提升代码可扩展性与可维护性;④掌握工厂模式与对象管理的基本设计思路。 阅读建议:此资源强调理论与实践结合,建议读者在理解概念的基础上动手实现文中示例代码,重点关注虚函数调用流程、抽象类设计与多态应用场景,并尝试扩展图形编辑工具功能(如新增图形类型、实现序列化等),以加深对C++面向对象机制的理解。
是Visual C++ 6.0程序设计学与用教程(起跑线)的源码.本书包括内容 Java语言是目前最为流行和通用的网络编程设计语言,在Internet上有着重要而广泛的应用。本书在第一版的基础上结合新版的JDK1.4对所有例程重新编译运行,并进行了一些必要的修订。本书全面介绍了Java语言的特点和功能,主要包括Java编程基础知识、Java算术运算符、Java编程语法、面向对象程序设计基本概念、系统类的使用和应用、图形用户界面设计、图形处理、多媒体处理、异常处理、多线程、网络编程、输入输出处理与序列化、Java本机接口、数据库编程等。 书评: 目录: 第1章 Java简介 1.1 概述 1.2 Java应用程序和小程序 1.3 创建第一个Java应用程序 1.4 创建第一个Java Applet应用程序 第2章 Java程序开发软硬件环境 2.1 硬件和软件环境 2.2 Java运行环境安装 2.3 设置环境变量 第3章 Java数据类型 3.1 数据类型综述 3.2 简单数据类型的实例化——变量与常量 3.3 整型常量和变量 3.4 浮点型常量和变量 3.5 字符型常量和变量 3.6 布尔型常量和变量 3.7 各类型数据间的优先关系和相互转换 第4章 运算符与表达式 4.1 算术运算符 4.2 关系运算符 4.3 布尔逻辑运算符 4.4 位运算符 4.5 赋值运算符 4.6 字符串运算符 4.7 扩展赋值运算符 4.8 条件运算符 4.9 其他运算符 4.10 表达式 4.11 注释 第5章 流程控制语句 5.1 结构化程序设计的3种基本流程 5.2 选择语句 5.3 循环语句 5.4 跳转语句 第6章 数组 6.1 一维数组 6.2 多维数组 6.3 字符串数组 第7章 面向对象和类的概念 7.1 面向对象程序设计基本概念 7.2 类 7.3 成员变量 7.4 方法 7.5 构造函数 第8章 类的继承性和多态性 8.1 类的继承 8.2 类的多态 第9章 包、接口和异常 9.1 包 9.2 接口 9.3 异常 第10章 Java系统类库 10.1 Java的类库结构 10.2 语言基础类库 10.3 工具类库 第11章 图形用户界面 11.1 常用组件 11.2 组件布局管理 第12章 窗口、菜单和对话框 12.1 窗口 12.2 菜单 12.3 对话框 第13章 图形处理 13.1 基本图形 13.2 画布 13.3 文字输出 13.4 绘图模式控制 第14章 多媒体编程 14.1 图像 14.2 动画制作 14.3 数字音频 第15章 多线程编程 15.1 多线程的主要概念 15.2 多线程的实现 15.3 多线程的同步 15.4 线程组 第16章 网络编程 16.1 URL编程 16.2 底层网络通信编程 第17章 输入/输出处理与序列化 17.1 输入/输出基础 17.2 字节流类 17.3 字符流 17.4 控制台输入/输出 17.5 序列化 第18章 使用Java本机接口(JNI) 18.1 JNI概述 18.2 使用本机方法编写Java程序 18.3 集成Java程序与本机方法 18.4 在本机方法中访问Java程序 第19章 数据库编程 19.1 概述 19.2 访问数据库的步骤 19.3 JDBC的特性 19.4 获取数据库信息 附录A JDK新特性简介

16,551

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Creator Browser
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧