深入浅出MFC第2版(PDF格式)-第95部分
按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!
470
…………………………………………………………Page 533……………………………………………………………
第8章 Document…View 深入探討
究竟是否Serializable,必须视其内含对象而定。举个例,如果一个typed pointer array
是以CObArray 为基础,那么它是Serializable;如果它是以CPtrArray 为基础,那么它
就不是Serializable。一般而言,Ptr 都不能够被Serialized。
虽然它是non…template,但如果照预定计划去使用它(例如以CByteArray 储存bytes,
而不是用来储存char),那么它还是type…safe 的。
手册上说它并非Serializable,但我存疑。各位不妨试验之。
Template…Based Classes
本书第2章末尾已经介绍过所谓的C++ template。MFC 的collection classes 里头有一些
是template…based ,对于类型检验的功夫做得比较好。这些类别区分为:
■ 简单型CArray、CList、CMap。它们都衍生自CObject,所以它们都具备了
文件读写、执行时期型别鉴识、动态生成等性质。
■ 类型指针型CTypedPtrArray、CTypedPtrList、CTypedPtrMap 。这些类别要求
你在参数中指定基础类别, 而基础类别必须是MFC 之中的non…template
pointer collections ,例如CObList 或CPtrArray 。你的新类别将继承基础类别
的所有性质。
Template…Based Classes 的使用方法 (注意:需包含afxtempl。h ,如p。903 stdafx。h )
简单型template…based classes 使用时需要指定参数:
■ CArray
■ CList
■ CMap
其中TYPE 用来指定你希望收集的对象的类型,它们可以是:
■ C++ 基础型别,如int、char、long、float 等等。
■ C++ 结构或类别。
471
…………………………………………………………Page 534……………………………………………………………
第篇 深入 MFC 程式設計
ARG_TYPE 则用来指定函数的参数类型。举个例,下面程序码表示我们需要一个int 阵
列,数组成员函数(例如Add )的参数是int:
CArray m_intArray;
m_intArray。Add(15);
再举一例,下面程序码表示我们需要一个由int 组成的串行,串行成员函数(例如
AddTail )的参数是int:
CList m_intList;
m_intList。AddTail(36);
m_intList。RemoveAll();
再举一例,下面程序码表示我们需要一个由CPoint 组成的数组,数组成员函数(例如
Add )的参数是CPoint:
CArray m_pointArray;
CPoint point(18; 64);
m_pointArray。Add(point);
「类型指针」型的template…based classes 使用时亦需指定参数:
■ CTypedPtrArray
■ CTypedPtrList
■ CTypedPtrMap
其中TYPE 用来指定你希望收集的对象的类型,它们可以是:
■ C++ 基础型别,如int、char、long、float 等等。
■ C++ 结构或类别。
BASE_CLASS 则用来指定基础类别,它可以是任何用来收集指针的non…template
collection classes ,例如CObList 或CObArray 或CPtrList 或CPtrArray 等等。举个
例子,下面程序码表示我们需要一个衍生自CObList 的类别,用来管理一个串行,而串
列组成份子为CStroke*:
CTypedPtrList m_strokeList;
CStroke* pStrokeItem = new CStroke(20);
m_strokeList。AddTail(pStrokeItem);
472
…………………………………………………………Page 535……………………………………………………………
第8章 Document…View 深入探討
CScribbleDoc 的修改
了解了Collection Classes 中各类别的特性以及所谓template/nontemplate 版本之后,以
本例之情况而言,很显然:
■不定量的线条数可以利用串行( linked list )来表示,那么MFC 的CObList 恰
可用来表现这样的串行。CObList 规定其每个元素必须是一个「CObject 衍生
类别」的对象实体,好啊,没问题,我们就设计一个名为CStroke 的类别,
衍生自CObject,代表一条线条。为了type…safe ,我们选择template 版本,
所以设计出这样的Document :
class CScribbleDoc : public CDocument
{
。。。
public:
CTypedPtrList m_strokeList;
。。。
}
■线条由笔宽和坐标点构成,所以CStroke 应该有m_nPenWidth 成员变量,但
一长串的坐标点以什么来管理好呢?数组是个不错的选择,至于数组内要放什
么类型的资料,我们不妨先着一鞭,想想这些坐标是怎么获得的。这些坐标显
然是在鼠标左键按下时进入程序之中,也就是利用OnLButtonDown 函数的参
数CPoint。CPoint 符合前一节所说的数组元素类型条件,所以CStroke 的成
员变量可以这么设计:
protected:
UINT m_nPenWidth;
public:
CArray m_pointArray;
。。。
}
至于CPoint 实际内容是什么,就甭管了吧。
事实上CPoint 是一个由两个long 组成的结构,两个long 各代表x 和y 坐标。
473
…………………………………………………………Page 536……………………………………………………………
第篇 深入 MFC 程式設計
CScribble Step1 Document: (本图为了说明方便,以CObList 代替实际使用之CTypedPtrList)
这是一个CObList 对象
CObList::RemoveHead CObList 的每个元素都是一个CObject 指针。
把串行头之CObject 对象指针取出 我们令它指向CStroke 对象,合法,因为
CStroke 衍生自CObject 。
CScribbleDoc
CObList m_strokeList CObList::AddTail
CObList m_strokeList
(文件内含一个CObList 串行) 把一个CObject 对象指针
放入串行尾端。
这是一个CArray 对象
UINT m_nPenWidth (线条可以「CPoint 数组」表示)
(代表笔的宽度) (屏幕点坐标正是一个CPoint )
CArray::Add
把一个元素放入数组中。
CArray 的' '
这就是一个 运算子
可取出数组的元素。
CStroke
对象
图8…3a Scribble Step1 的文件由线条构成,线条又由点数组构成
CObject
CObject
CCmdTarget CTypedPtrList
CCmdTarget CTypedPtrList
CDocument CArray
CDocument CArray
CScribbleDoc CStroke : defined in Scribble
CScribbleDoc CStroke
。
图8…3b Scribble Step1 文件所使用的类别
474
…………………………………………………………Page 537……………………………………………………………
CScribbleDoc 内嵌一个CObList 对象,CObList 串行中的每个元素都是一个CStroke 对
象指针,而CStroke 又内嵌一个CArray 对象。下面是Step1 程序的Document 设计。
SCRIBBLEDOC。H (阴影表示与Step0的差异)
#0001 /////////////////////////////////////////////////////////////////
#0002 // class CStroke
#0003 //
#0004 // A stroke is a series of connected points in the scribble drawing。
#0005 // A scribble document may have multiple strokes。
#0006
#0007 class CStroke : public CObject
#0008 {
#0009 public:
#0010 CStroke(UINT nPenWidth);
#0011
#0012 protected:
#0013 CStroke();
#0014 DECLARE_SERIAL(CStroke)
#0015
#0016 // Attributes
#0017 protected:
#0018 UINT m_nPenWidth; // one pen width applies to entire stroke
#0019 public:
#0020 CArray m_pointArray; // series of connected
points
#0021
#0022 // Operations
#0023 public:
#0024 BOOL DrawStroke(CDC* pDC);
#0025
#0026 public:
#0027 virtual void Serialize(CArchive& ar);
#0028 };
#0029
#0030 /////////////////////////////////////////////////////////////////
#0031
#0032 class CScribbleDoc : public CDocument
#0033 {
#0034 protected: // create from serialization only
#0035 CScribbleDoc();
#0036 DECLARE_DYNCREATE(CScribbleDoc)
#0037
#0038 // Attributes
#0039 protected:
475
…………………………………………………………Page 538……………………………………………………………
第篇 深入 M