Dynamic Creation(动态创建)
程序执行期间,根据动态获得一个类名称,要求程序产生一个对象。“类别型录网”为此提供了基础。如果能够把类的大小记录在类别型录中,把建构函数(不是C++的构造函数,而是指即将出现的CRuntimeClass::CreateObject())也记录在类别型录中,当程序在执行期获得一个类名称,它就可以在“类别型录网”中找出对应的元素,然后调用其建构函数,产生出对象。
类别型录网的元素CRuntimeClass于是发生变化:
Struct CruntimeClass
{
//Attributes
LRCSTR m_lpnzClassName;
Int m_nObjectSize;
UINT m_wSchema; //schema number of the loaded class
CObject *(PASCAL * m_pfnCreateObject)();//NULL=>abstract class
CRuntimeClass *m_pBaseClass;
CObject *CreateObject();
Static CRuntimeClass *PASCAL Load();
//CruntimeClass objects linked together in the simple list
static CRuntimeClass *pFirstClass;
CRuntimeClass * m_pNextClass;
};
DECLARE_DYNCREATE/IMPLEMENT_DYNCREATE宏
为了适应CRuntimeClass中新增的成员变量,再新添加两个宏。DECLARE_DYNCREATE和IMPLEMENT_DYNCREATE:
#define DECLARE_DYNCREATE(class_name) /
DECLARE_DYNAMIC(class_name) /
Static CObject *PASCAL CreateObject();
#define IMPLEMENT_DYNCREATE(class_name, base_class_name) /
CObject *PASCAL class_name::CreateObject() /
{ return new class_name; }/
_IMPLEMENT_RUNTIMECLASS(class_name,base_class_name,0xFFFF,/
class_name::CreateObject)
以CframeWnd为例,程序如下:
class CframeWnd : public CWnd
{
DECLARE_DTNCREATE(CFrameWnd);
…
};
IMPLEMENT_DYNCREATE(CframeWnd,CWnd)
展开如下:
class CframeWnd : public CWnd
{
public:
static CRuntimeClass ClassCFrameWnd;
virtual CRuntimeClass *GetRuntimeClass() const;
static CObject *PASCAL CreateObject();
…
};
CObject *PASCAL CframeWnd;;CreateObject()
{ return new CframeWnd; }
static char _lpszCFrameWnd[] = “CFrameWnd”;
CRuntimeClass CframeWnd::classCFrameWnd = { _lpszCFrameWnd,sizeof(CFrameWnd),
0XFFFF,CframeWnd::CreateObject,RUNTIME_CLASS(CWnd),NULL };
static AFX_CLASSINIT _init_CframeWnd(&CframeWnd::classCFrameWnd);
CRuntimeClass * CframeWnd::GetRuntimeClass() const
{ return &CframeWnd::classCFrameWnd;}
从宏的定义可以清楚的看到,拥有动态创建(Dynamic Creation)能力的类库,必然拥有RTTI能力.因为_DYNCREATE宏覆盖了_DYNAMIC宏.
范例程序
MFC.H
#define BOOL int
#define TURE 1
#define FALSE 0
#define LPCSTR LPSTR
#define char * LPSTR;
#define UINT int
#define PASCAL _stdcall
#define TRACE1 printf
#include <iostream.h>
#include <stdio.h>
#include <string.h>
class CObject
Struct CruntimeClass
{
//Attributes
LRCSTR m_lpnzClassName;
Int m_nObjectSize;
UINT m_wSchema; //schema number of the loaded class
CObject *(PASCAL * m_pfnCreateObject)();//NULL=>abstract class
CRuntimeClass *m_pBaseClass;
CObject * CreateObject();
Static CRuntimeClass *PASCAL Load();
//CruntimeClass objects linked together in the simple list
static CRuntimeClass *pFirstClass;
CRuntimeClass * m_pNextClass;
}
Struct AFX_CLASSINIT
{ AFX_CLASSINIT(CRuntimeClass *pNewClass);};
#define RUNTIME_CLASS(class_name) /
(&class_name::class##class_name)
#define DECLARE_DYNAMIC(class_name) /
public: /
static CRuntimeClass class##class_name; /
virtual CRuntimeClass * GetRuntimeClass() const;
#define DECLARE_DYNCREATE(class_name) /
DECLARE_DYNAMTIC(class_name) /
Static CObject *PASCAL CreateObject();
#define _IMPLEMENT_RUNTIMECLASS(class_name,base_class_name,wSchema,pfnNew) /
static char lpsz##classname[] = #class_name; /
CRuntimeClass class_name::class##class_name = ( /
lpsz##class_name ,sizeof(class_name),wSchema,pfnNew,/
RUNTIME_CLASS(base_class_name),NULL);/
Static AFX_CLASSINIT _init_##class_name(&class_name::class##class_name);/
CRuntimeClass * class_name::GetRuntimeClass() const /
{return &class_name::class##class_name;}/
#define IMPLEMENT_DYNAMIC(class_name , base_class_name) /
_IMPLEMENT_RUNTIMECLASS(class_name,base_class_name,0xFFFF,NULL)
#define IMPLEMENT_DYNCREATE(class_name,base_class_name)/
CObject *PASCAL class_name::CreateObject() /
{ return new class_name; } /
_IMPLEMENT_RUNTIMECLASS(class_name,base_class_name,0XFFFF,/
class_name::CreateObject)
class CObject
{
public:
CObject::CObject() { }
CObject::~CObject() { }
Virtual CRuntimeClass *GetRuntimeClass() const;
BOOL IsKindOf(const CRuntimeClass *pCLass) const;
Public:
static CRuntimeClass classCObject;
virtual void Sayhell() {cout<<”Hello CObject/n”;}
};
class CCmdTarget : public CObject
{
DECLARE_DYNAMIC(CCmdTarget)
public:
CCmdTarget:: CCmdTarget () { }
CCmdTarget::~CCmdTarget () { }
};
class CwinThread : public CCmdTarget
{
DECLARE_DYNAMIC(CWinThread)
public:
CwinThread:: CwinThread () { }
CwinThread::~ CwinThread () { }
Virtual BOOL InitInstance(){
Return TRUE;
}
virtual int Run(){
return 1;
}
};
class CWnd;
class CWinApp : public CwinThread
{
DECLARE_DYNAMIC(CWinApp)
public:
CWinApp * m_pCurrentWinApp;
CWnd * m_pMainWnd;
Public:
CWinApp::CWinApp() { pCurrentWinApp = this ;}
CWinApp::~CWinApp() { }
virtual BOOl InitApplication () {
Return TRUE;
}
virtual BOOL InitInstance () {
return TRUE;
}
virtual int Run () {
return CWinThread::Run();
}
};
Class CDocument : public CCmdTarget
{
DECLARE_DYNAMIC(CDocument)
public:
Cdocument:: Cdocument() { }
Cdocument::~ Cdocument() { }
};
Class CWnd : public CCmdTarget
{
DECLARE_DYNCREATE(CWnd)
public:
CWnd:: CWnd () { }
CWnd::~CWnd () { }
Virtual BOOL Create();
BOOL CreateEx();
virtual BOOL PreCreateWindow();
void SayHello() {cout<<”Hello CWnd/n”;}
};
Class CFrameWnd : public CWnd
{
DECLARE_DYNCREATE(CFrameWnd)
public:
CFrameWnd:: CFrameWnd () { }
CFrameWnd::~CFrameWnd () { }
BOOL Create ();
Virtual BOOL PreCreateWindow();
void SayHello() {cout<<”Hello CFrameWnd/n”;}
};
Class CView : public CWnd
{
DECLARE_DYNAMIC(CView)
public:
CView:: CView () { }
CView::~ CView () { }
};
//global function
CWinApp *AfxGetApp();
MFC.CPP
#include “my.h” //本该包含mfc.h,但为了CmyWinapp的定义
extern CmyWinApp theApp ; //external global object
static char szCObject[] = “CObject”;
struct CRuntimeClass CObject::classCObject =
{szCObject,sizeof( CObject),0XFFFF,NULL,NULL,NULL };
static AFX_CLASSINIT _init_CObject(&CObject::classCObject);
CRuntimeClass *CRuntimeClass::pFirstClass = NULL;
AFX_CLASSINIT::AFX_CLASSINIT(CRuntimeClass * pNewClass)
{
pNewClass->m_pNextclass=CRuntimeClass ::pFirstClass;
CRuntimeClass::pFirstClass = pNewClass;
}
CObject *CRuntimeClass::CreateObject()
{
if(m_pfnCreateObject == NULL )
{
TRACE1(“Error:Trying to create object which is not DECLARE_DYNCREATE nor
DECLARE_DYNAMIC:%hs./n”,m_lpsClassName);
Return NULL;
}
CObject *pObject = NULL;
PObject = (*m_pfnCreateObject)();
Return pObject;
}
CRuntimeClass *PASCAL CRuntimeClass::Load()
{
char szClassName[64];
CRuntimeClass *pClass;
cout<<”enter a class name…”;
cin>>szClassName;
for(pClass=pFirstClass;pClass!=NULL;pClass=pClass)
{
if(strcmp(szClassName,pClass->m_lpszClassName)==0)
return pClass;
}
TRACE1(“Erroe:class not found:%s /n”,szClassName);
Return NULL;
}
CRuntimeClass *CObject::GetRuntimeClass() const
{
return &CObject::classCObject;
}
BOOL CWnd::Create()
{
return TRUE;
}
BOOL CWnd::CreateEx()
{
PreCreateWindow();
return TRUE;
}
BOOL CWnd::PreCreateWindow()
{
return TRUE;
}
BOOL CframeWnd::Create()
{
CreateEx();
return TRUE;
}
BOOL CframeWnd::PreCreateWindow()
{
return TRUE;
}
INPLEMENT_DYNAMIC(CcmdTarget,CObject)
INPLEMENT_DYNAMIC(CWinThread, CcmdTarget)
INPLEMENT_DYNAMIC(CWinAPP, CWinThread)
INPLEMENT_DYNAMIC(CWnd,CCmdTarget)
INPLEMENT_DYNCREATE(CFrameWnd, CWnd)
INPLEMENT_DYNAMIC(CDocument, CcmdTarget)
INPLEMENT_ DYNCREATE(CView,CWnd)
//global function
CWinApp * AfxApp()
{
return theApp.m_pCurrentWinApp;
}
MY.H
#include <iostream.h>
#include “mfc.h”
class CmyWinApp : public CWinApp
{
public:
CmyWinApp:: CmyWinApp() { }
CmyWinApp::~ CmyWinApp() { }
virtual BOOL InitInstance();
};
class CMyFrameWnd : public CframeWnd
{
DECLARE_DYNCREATE(CMyFrameWnd)
public:
CMyFrameWnd();
~CMyFrameWnd() {}
void SayHello() {cout<<”Hello CmyFrameWnd/n”;}
};
class CmyDoc : public Cdocument
{
DECLARE_DYNCREATE(CMyDoc)
public:
CmyDoc:: CmyDoc() { }
CmyDoc::~ CmyDoc() { }
void SayHello() {cout<<”Hello CMyDoc/n”;}
};
class CMyView : public CView
{
DECLARE_DYNCREATE(CMyView)
public:
CMyView:: CMyView () { }
CMyView::~ CMyView () { }
void SayHello() {cout<<”Hello CMyView/n”;}
};
//global function
coid PrintAllClasses()
MFC.CPP
#include “my.h”
CmyWinApp theApp; //global object
BOOL CMyWinAPP::InitInstance()
{
m_pMainWnd = new CmyFrameWnd;
return TRUE;
}
CmyFrameWnd::CmyFrameWnd()
{
Create();
}
IMPLEMENT_DYNCREATE(CmyFrameWnd,CFrameWnd)
IMPLEMENT_DYNCREATE(CMyDoc,CDocument)
IMPLEMENT_DYNCREATE(CMyView,CView)
void PrintAllClasses()
{
CRuntimeClass *pClass;
//just walk through the simple list of regidtered classes
for(pClass = CRuntimeClass::pFirstClass;pClass!=NULL;
pClass = pCLass->m_pNextClass)
{
cout<<pClass->m_lpszClassName<<”/n”;
cout<<pClass->m_nObjectSize<<”/n”;
cout<<pClass->m_wSchema<<”/n”;
}
}
//main()
void main()
{
CwinApp *pApp = AfxGetApp();
pApp->InitApplication();
pApp->InitInstance();
pApp->Run();
CRuntimeClass *pClassRef;
CObject *pObj;
While(1)
{
if((pClassRef=CRuntimeClass::Load())==NULL)
break;
pObj = pClassRef->CreateObject();
if(pObj!=NULL)
pObj->SayHello();
}
}