在MFC application framework 中,动态创建依然是依靠宏的方式来实现的。在仿真的过程中依然可以使用CRuntimeClass这个类来进行类型的识别和动态创建。CRuntimeClass类的声明如下:
struct CRuntimeClass
{
// Attributes
LPCSTR m_lpszClassName;
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 simple list
static CRuntimeClass* pFirstClass; // start of class list
CRuntimeClass* m_pNextClass; // linked list of registered classes
};
对比在RTTI中使用的CRuntimeClass,添加了成员CObject* CreateObject和静态成员CRuntimeClass* PASCAL Load() 。 前者用于动态创建对象。后者用于返回满足条件的CRuntimeClass * 。
动态创建的过程和RTTI 的过程有些类似,都是在类的声明中加入一些成员。并依靠宏在实现文件中,进行初始化。建立与RTTI中相同的型录,并依靠该型录对指定了类进行创建和使用。
源码:
MFC.H
#define BOOL int
#define TRUE 1
#define FALSE 0
#define LPCSTR LPSTR
typedef 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
LPCSTR m_lpszClassName;
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 simple list
static CRuntimeClass* pFirstClass; // start of class list
CRuntimeClass* m_pNextClass; // linked list of registered classes
};
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_DYNAMIC(class_name) /
static CObject* PASCAL CreateObject();
#define _IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, wSchema, pfnNew) /
static char _lpsz##class_name[] = #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 SayHello() { 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() {
m_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() {
cout << "CWnd Constructor /n";
}
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() {
cout << "CFrameWnd Constructor /n";
}
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" // it should be mfc.h, but for CMyWinApp definition, so...
extern CMyWinApp theApp;
static char szCObject[] = "CObject";
struct CRuntimeClass CObject::classCObject =
{ szCObject, sizeof(CObject), 0xffff, 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_SERIAL: %hs./n",
m_lpszClassName);
return NULL;
}
CObject* pObject = NULL;
pObject = (*m_pfnCreateObject)();
return pObject;
}
CRuntimeClass* PASCAL CRuntimeClass::Load()
{
char szClassName[64];
CRuntimeClass* pClass;
// JJHOU : instead of Load from file, we Load from cin.
cout << "enter a class name... ";
cin >> szClassName;
for (pClass = pFirstClass; pClass != NULL; pClass = pClass->m_pNextClass)
{
if (strcmp(szClassName, pClass->m_lpszClassName) == 0)
return pClass;
}
TRACE1("Error: Class not found: %s /n", szClassName);
return NULL; // not found
}
CRuntimeClass* CObject::GetRuntimeClass() const
{
return &CObject::classCObject;
}
BOOL CObject::IsKindOf(const CRuntimeClass* pClass) const
{
CRuntimeClass* pClassThis = GetRuntimeClass();
while (pClassThis != NULL)
{
if (pClassThis == pClass)
return TRUE;
pClassThis = pClassThis->m_pBaseClass;
}
return FALSE; // walked to the top, no match
}
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;
}
CWinApp* AfxGetApp()
{
return theApp.m_pCurrentWinApp;
}
IMPLEMENT_DYNAMIC(CCmdTarget, CObject)
IMPLEMENT_DYNAMIC(CWinThread, CCmdTarget)
IMPLEMENT_DYNAMIC(CWinApp, CWinThread)
IMPLEMENT_DYNAMIC(CDocument, CCmdTarget)
IMPLEMENT_DYNCREATE(CWnd, CCmdTarget)
IMPLEMENT_DYNAMIC(CView, CWnd)
IMPLEMENT_DYNCREATE(CFrameWnd, CWnd)
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() {
cout << "CMyDoc Constructor /n";
}
CMyDoc::~CMyDoc() {
}
void SayHello() { cout << "Hello CMyDoc /n"; }
};
class CMyView : public CView
{
DECLARE_DYNCREATE(CMyView)
public:
CMyView::CMyView() {
cout << "CMyView Constructor /n";
}
CMyView::~CMyView() {
}
void SayHello() { cout << "Hello CMyView /n"; }
};
// global function
void AfxPrintAllClasses();
MY.CPP----------------------------------
#include "my.h"
CMyWinApp theApp;
BOOL CMyWinApp::InitInstance()
{
m_pMainWnd = new CMyFrameWnd;
return TRUE;
}
CMyFrameWnd::CMyFrameWnd()
{
cout << "CMyFrameWnd Constructor /n";
Create();
}
IMPLEMENT_DYNCREATE(CMyFrameWnd, CFrameWnd)
IMPLEMENT_DYNCREATE(CMyDoc, CDocument)
IMPLEMENT_DYNCREATE(CMyView, CView)
void PrintAllClasses()
{
CRuntimeClass* pClass;
// just walk through the simple list of registered 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();
//Test Dynamic Creation
CRuntimeClass* pClassRef;
CObject* pOb;
while(1)
{
if ((pClassRef = CRuntimeClass::Load()) == NULL)
break;
pOb = pClassRef->CreateObject();
if (pOb != NULL)
pOb->SayHello();
}
}
//------------------------------------------------------------------
struct CRuntimeClass
{
// Attributes
LPCSTR m_lpszClassName;
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 simple list
static CRuntimeClass* pFirstClass; // start of class list
CRuntimeClass* m_pNextClass; // linked list of registered classes
};
对比在RTTI中使用的CRuntimeClass,添加了成员CObject* CreateObject和静态成员CRuntimeClass* PASCAL Load() 。 前者用于动态创建对象。后者用于返回满足条件的CRuntimeClass * 。
动态创建的过程和RTTI 的过程有些类似,都是在类的声明中加入一些成员。并依靠宏在实现文件中,进行初始化。建立与RTTI中相同的型录,并依靠该型录对指定了类进行创建和使用。
源码:
MFC.H
#define BOOL int
#define TRUE 1
#define FALSE 0
#define LPCSTR LPSTR
typedef 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
LPCSTR m_lpszClassName;
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 simple list
static CRuntimeClass* pFirstClass; // start of class list
CRuntimeClass* m_pNextClass; // linked list of registered classes
};
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_DYNAMIC(class_name) /
static CObject* PASCAL CreateObject();
#define _IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, wSchema, pfnNew) /
static char _lpsz##class_name[] = #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 SayHello() { 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() {
m_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() {
cout << "CWnd Constructor /n";
}
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() {
cout << "CFrameWnd Constructor /n";
}
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" // it should be mfc.h, but for CMyWinApp definition, so...
extern CMyWinApp theApp;
static char szCObject[] = "CObject";
struct CRuntimeClass CObject::classCObject =
{ szCObject, sizeof(CObject), 0xffff, 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_SERIAL: %hs./n",
m_lpszClassName);
return NULL;
}
CObject* pObject = NULL;
pObject = (*m_pfnCreateObject)();
return pObject;
}
CRuntimeClass* PASCAL CRuntimeClass::Load()
{
char szClassName[64];
CRuntimeClass* pClass;
// JJHOU : instead of Load from file, we Load from cin.
cout << "enter a class name... ";
cin >> szClassName;
for (pClass = pFirstClass; pClass != NULL; pClass = pClass->m_pNextClass)
{
if (strcmp(szClassName, pClass->m_lpszClassName) == 0)
return pClass;
}
TRACE1("Error: Class not found: %s /n", szClassName);
return NULL; // not found
}
CRuntimeClass* CObject::GetRuntimeClass() const
{
return &CObject::classCObject;
}
BOOL CObject::IsKindOf(const CRuntimeClass* pClass) const
{
CRuntimeClass* pClassThis = GetRuntimeClass();
while (pClassThis != NULL)
{
if (pClassThis == pClass)
return TRUE;
pClassThis = pClassThis->m_pBaseClass;
}
return FALSE; // walked to the top, no match
}
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;
}
CWinApp* AfxGetApp()
{
return theApp.m_pCurrentWinApp;
}
IMPLEMENT_DYNAMIC(CCmdTarget, CObject)
IMPLEMENT_DYNAMIC(CWinThread, CCmdTarget)
IMPLEMENT_DYNAMIC(CWinApp, CWinThread)
IMPLEMENT_DYNAMIC(CDocument, CCmdTarget)
IMPLEMENT_DYNCREATE(CWnd, CCmdTarget)
IMPLEMENT_DYNAMIC(CView, CWnd)
IMPLEMENT_DYNCREATE(CFrameWnd, CWnd)
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() {
cout << "CMyDoc Constructor /n";
}
CMyDoc::~CMyDoc() {
}
void SayHello() { cout << "Hello CMyDoc /n"; }
};
class CMyView : public CView
{
DECLARE_DYNCREATE(CMyView)
public:
CMyView::CMyView() {
cout << "CMyView Constructor /n";
}
CMyView::~CMyView() {
}
void SayHello() { cout << "Hello CMyView /n"; }
};
// global function
void AfxPrintAllClasses();
MY.CPP----------------------------------
#include "my.h"
CMyWinApp theApp;
BOOL CMyWinApp::InitInstance()
{
m_pMainWnd = new CMyFrameWnd;
return TRUE;
}
CMyFrameWnd::CMyFrameWnd()
{
cout << "CMyFrameWnd Constructor /n";
Create();
}
IMPLEMENT_DYNCREATE(CMyFrameWnd, CFrameWnd)
IMPLEMENT_DYNCREATE(CMyDoc, CDocument)
IMPLEMENT_DYNCREATE(CMyView, CView)
void PrintAllClasses()
{
CRuntimeClass* pClass;
// just walk through the simple list of registered 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();
//Test Dynamic Creation
CRuntimeClass* pClassRef;
CObject* pOb;
while(1)
{
if ((pClassRef = CRuntimeClass::Load()) == NULL)
break;
pOb = pClassRef->CreateObject();
if (pOb != NULL)
pOb->SayHello();
}
}
//------------------------------------------------------------------