什么是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 阅读(2092)
评论(0) 编辑 收藏 引用 所属分类:
MFC