随笔-80  评论-22  文章-0  trackbacks-0

什么是application framework?内部运作机制是什么?

MFC六大关键技术是什么?
1MFC程序的初始化过程
2RTTI 动态类型标识 
3Dynamic Creation  动态生成
4Persistence  永久保留
5Message Mapping  信息映射
6Message Routing   信息传递


怎样自制RTTI?
我们作为类库的设计者要在类构造起来的时候,记录必要的信息,以建立型录。型录中的类的信息,最好以链表方式连接起来。一般“类别型录”是一个结构,其中至少需要类名字,链表的Next指针,以及链表的First指针。First属于整体变量,一份就好,所以用static修饰。
为了将每一个类都能拥有成员变量集合,并且最好有一定的命名规则,然后经某种手段将整个类库构造好之后,“类别型录”(就是各个CRuntimeClass对象)则能呈现为:


什么是DECLARE_DYNAMIC/IMPLEMENT_DYNAMIC 宏?作用就是完成RTTI的“类别型录”。
为了将一个类对象塞到类之中,并定义一个可以捕捉到该对象地址的函数,定义一个宏为:
#define DECLARE_DYNAMIC(class_name)
public:
static CRuntimeClass class##class_name;
virtual CRuntimeClass* GetRuntimeClass()const;

比如我使用了DECLARE_DYNAMIC(CView)
编译器预处理器为我做出的代码是:
public:
 static CRuntimeClass classCView;
 virtual CRuntimeClass * GetRuntimeClass()const;
也就是定义类时,将类放入DECLARE_DYNAMIC宏就是把要放的对象放到了里边。具体连接工作是由IMPLEMENT_DYNAMIC宏来实现:
#define IMPLEMENT_DYNAMIC(class_name,base_class_name)
 _IMPLEMENT_RUNTIMECLASS(class_name,base_class_name,0xFFFF,NULL)
这里不做扩展,总之,IMPLEMENT_DYNAMIC内容不仅制定初值,它使用了一个struct AFX_CLASSINIT {AFX_CLASSINTI(CRuntimeClass * pNewClass);};
(c++的struct和class都有构造函数):
AFX_CLASSINIT::AFX_CLASSINIT(CRuntimeClass*pNewClass)
{ pNewClass->m_NextClass = CRuntimeClass::pFirstClass;
  CRuntimeClass::pFirstClass = pNewClass;
}
就是上边的这个构造函数完成了连接工作。
一般使用的形式是:
class CView:public CWnd
{
 DECLARE_DYNAMIC(CView)
 ...
};
// in implementation file
IMPLEMENT_DYNAMIC(CView CWnd)
这两个宏就完成了构造数据链表的工作。

怎样生成mfc层次结构的类别型录?

.h文件中
class CObject{...};
class CCmdTarget:public CObject
{
 DECLARE_DYNCMIC (CCmdTarget)
 ...
};
class CWinThread:public CCmdTarget
{
 DECLARE_DYNAMIC (CWinThread)
 ...
};
class CWinApp:public CWinThread
{
 DECLARE_DYNAMIC (CWinApp)
 ...
};
class CDocument:public CCmdTarget
{
 DECLARE_DYNAMIC (CDocument)
 ... 
};
class CWnd:public CCmdTarget
{
 DECLARE_DYNAMIC (CWnd)
 ...
};
class CFrameWnd:public CWnd
{
 DECLARE_DYNAMIC (CFrameWnd)
 ...
};
class CView:public CWnd
{
 DECLARE_DYNAMIC (CView)
 ...
};
class CMyWinApp:public CWinApp
{...};
class CMyFrameWnd:public CFrameWnd
{...};
class CMyDoc:public CDocument
{...};
class CMyView:public CView
{...};


.cpp文件中
IMPLEMENT_DYNAMIC(CCmdTarget,CObject)
IMPLEMENT_DYNAMIC(CWinThread,CCmdTarget)
IMPLEMENT_DYNAMIC(CWinApp,CWinThread)
IMPLEMENT_DYNAMIC(CWnd,CCmdTarget)
IMPLEMENT_DYNAMIC(CView,CWnd)
IMPLEMENT_DYNAMIC(CFrameWnd,CWnd)
IMPLEMENT_DYNAMIC(CDocument,CCmdTarget)


IsKindOf是什么?
它是类型识别,就说在建立了“类别型录”网后,在某个类中存在这个函数,就是看这个指针是不是存在某个类的下支中。
比如:
CMyDoc * pMyDoc = new CMyDoc;
CMyView * pMyView = new CMyView;

cout<<pMyDoc->IsKindOf(RUNTIME_CLASS(CMyDoc));//TURE
cout<<pMyDoc->IsKindOf(RUNTIME_CLASS(CDocument));//TURE
cout<<pMyDoc->IsKindOf(RUNTIME_CLASS(CCmdTarget));//TURE
cout<<pMyDoc->IsKindOf(RUNTIME_CLASS(CObject));//TURE
cout<<pMyDoc->IsKindOf(RUNTIME_CLASS(CWinApp));//FALSE


怎样 自制Dynamic Create(动态生成)?

将类的大小记录在类别型录中,把构造函数也记录在类别型录中,当程序在运行时期获得一个类名字,它就可以在“类别型录网”中找到对应的元素,然后根据类的大小,调用构造函数,产生出该对象。

这里使用的是DECLARE_DYNCREATE/IMPLEMENT_DYNCREATE宏
使用和完成类别型录的方式差不多:
class CFrameWnd:public CWnd
{
 DECLARE_DYNCREATE(CFrameWnd)
 ...
};(就是在头文件中)

// in implement (就是在cpp文件中实现)
IMPLEMENT_DYNCREATE(CFrameWnd,CWnd)


怎样自制Persistence(永久保存)机制?
写到文件中去。
把数据写到文件中。方法是:在Document/View结构中,数据都放在一份document里头,我们只要把其中的成员变量陆续写进文件中即可。如果成员变量是个对象,就需要先记载类的名字,然后才是对象中的数据。


什么是Serialize机制?
就是把文件名的选择、文件的访问、缓冲区的建立、数据的读写、运算符(>>)和运算符(<<)的重载、对象的动态生成都包装起来。它的数据读写和对象的动代生成是关键,动态生成已经具有,这里就重点讨论数据的读写操作。

serialize机制就是考虑到每次记录对象内容的时候,先写入一个代码,表示此对象类是否曾在文件中记录过了。如果是新类,就记录类的名字,如果是就类,就用代码表示。还有就是可以控制版本号的问题。有一个专门的serialization函数,用于负责这些任务。
每一个可写到文件或可从文件中读出的类,都应该有它自己的serailize函数。负责它自己数据读写操作,并且应该改写“<<”“>>”,把数据导流导archive中。


怎样完成serialize?
使用DECLARE_SERIAL/IMPLEMENT_SERIAL宏。这个宏的功能是将“<<”和“>>”两个运算符重载,还可以将serialize函数放到类定义中。类能够进行文件读写,其前提是拥有动态生成的能力。
#define DECLARE_SERIAL(class_name)
 DECLARE_DYNCREATE(class_name)
 friend CArchive& AFXAPI operator >>(CArchive& ar,class_name *&pOb)
#define IMPLEMENT_SERIAL(class_name,base_name,wSchema)
 CObject * PASCAL class_name::CreateObject()
 {return new class_name;}
 _IMPLEMENT_RUNTIMECLASS(class_name,base_class_name,wSchema,
  class_name::CreateObject)
 CArchive& AFXAPI operator>>(CArchive& ar,class_name *&pOb)
 {pOb = (class_name*)ar.ReadObject(RUNTIME_CLASS(class_name));
 return ar;}


一个对象处理之前,判断是否第一次出现、记录版本号、记录文件名怎样实现?
用CRuntimeClass中的两个函数Load和Store。
struct CRuntimeClass
{
//attributes
 LPCSTR m_lpszClassName;
 int m_nObjectSize;
 UINT m_wSchema;//schema number of the loaded class
 CObject *(PASCAL * m_pfnCreateObject)();
 CRuntimeClass * m_pBaseClass;
  
 CObject *CreateObject();
 void Store (CArchive&ar)const;
 static CRuntimeClass * PASCAL Load(CArchive &ar,UINT *pwSchemaNum);
//CRuntimeClass objects linked together in simple list
 static CRuntimeClass * pFirstClass;//start of class list
 CRuntimeClass * m_pNextClass;//linked list of registered classes
};


为了让整个serialization机制运行起来,必须做定义为:
.h文件中必须有
class CScribDoc:public CDocument
{
 DECLARE_DYNCREATE(CScribDoc)
 ...
};
class CStroke:public CObject
{
 DECLARE_SERIAL(CStroke)
public:
 void Serialize(CArchive&);
...
};

class CRectangle :public CObject
{
 DECLARE_SERIAL(CRectangle)
public
 void Serialize(CArchive&)

};

class CCircle:public CObjcet
{
 DECLARE_SERIAL(CCircle)
public:
 void Seiralize(CArchive&);
...
};

.cpp文件中必须有
IMPLEMENT_DYNCREATE(CScribDoc,CDocument)
IMPLEMENT_SERIAL(CStroke,CObjcet,2)
IMPLEMENT_SERIAL(CRectangle,CObjcet,1)
IMPLEMENT_SERIAL(CCircle,CObjcet,1)


怎样自制Message Mapping(消息映射)?

当我们的类库成立,如果其中与信息有关的类(就是“信息标的类”mfc中就是CCmdTarget)都是一条链式地继承,我们应该为每一个“信息表的类”准备一个信息映射表,比且将基类与派生类的信息映射表连接起来。然后,当窗口函数做信息的比较时,我们就可以想办法引导它沿着这条路走过去。

定义消息映射的数据结构:
struct AFX_MSGMAP
{
 AFX_MSGMAP * pBaseMessagMap;
 AFX_MSGMAP_ENTRY *lpEntries;
};
其中的AFX_MSGMAP_ENTRY又是另一个数据结构:
struct AFX_MSGMAP_ENTRY
{
 UINT nMessage;
 UINT nCode;
 UINT nID;
 UINT nLastID;
 UINT nSig;
 AFX_PMSG pfn;
}
其中的AFX_PMSG定义为函数指针:
typedef void (CCmdTarget::*AFX_PMSG)(void);

之后定义的宏就是
#define DECLARE_MESSAGE_MAP();
static AFX_MSGMAP_ENTRY_ messageEntries[];
static AFX_MSGMAP messageMap;
virtual AFX_MSGMAP *GetMessageMap()const;

MFC对消息传递的规定是什么?(message routing)
如果是一般的windows信息(WM_xxx),一定是从派生类流向基类。

posted on 2009-07-18 19:24 Bluesea 阅读(934) 评论(0)  编辑 收藏 引用 所属分类: MFC

只有注册用户登录后才能发表评论。
【推荐】超50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理