按照Frame3中的图(3-1)“类别型录”网,要实现 IsKindOf功能,再轻松不过了。
1)为CObject 加上一个 IsKindOf 函数,于是此函数将被所有类继承。它将把参数所指定的某个 CRuntimeClass对象拿来与类别型录中的元素一一比较。如果比较成功(即在类别型录里有存在),就传回TRUE;否则,传回FALSE。
// in header file
class CObject
{
public:
...
BOOL IsKindOf(const CRuntimeClass* pClass) const;
};
//in implementation file
BOOL CObject::IsKindOf(const CRuntimeClass* pClass) const //类型识别
{
CRuntimeClass* pClassThis = GetRuntimeClass();
while (pClassThis!=NULL)
{
if (pClassThis == pClass)
{
return TRUE;
}
pClassThis = pClassThis->m_pBaseClass;
}
return FALSE;
}
注意,while循环中所追踪的是“同宗”路线,也就是凭借着 m_pBaseClass而非m_pNextClass。假设我们调用的是:
CView* pView = new CView;
pView->IsKingOf(RUNTIME_CLASS(CWINAPP));
IsKindOf 的参数其实就是 &CWinApp::classCWinApp。函数内利用GetRuntimeClass先取得 &CView::classCView,然后循线而上(从图3-1来看,所谓的循线分别是CView、CWnd、CCmdTarget、CObject),每获得一个 CRuntimeClass对象指针,就拿来和 CView::classCView的指针比较。依照此思路,就完成了 IsKindOf函数。
2)IsKindOf的使用方式如下:
CMyDoc* pMyDoc = new CMyDoc;
CMyView* pMyView = new CMyView;
CWnd* pMyWnd = pApp->m_pMainWnd;
cout<<pMyDoc->IsKindOf(RUNTIME_CLASS(CMyDoc))<<"\n"; //为true
cout<<pMyDoc->IsKindOf(RUNTIME_CLASS(CDocument))<<"\n"; //为true
cout<<pMyDoc->IsKindOf(RUNTIME_CLASS(CCmdTarget))<<"\n"; //为true
cout<<pMyDoc->IsKindOf(RUNTIME_CLASS(CObject))<<"\n"; //为true
cout<<pMyDoc->IsKindOf(RUNTIME_CLASS(CWinApp))<<"\n"; //为false
cout<<pMyDoc->IsKindOf(RUNTIME_CLASS(CView))<<"\n\n"; //为false
cout<<pMyView->IsKindOf(RUNTIME_CLASS(CView))<<"\n"; //为true
cout<<pMyView->IsKindOf(RUNTIME_CLASS(CObject))<<"\n"; //为true
cout<<pMyView->IsKindOf(RUNTIME_CLASS(CWnd))<<"\n"; //为true
cout<<pMyView->IsKindOf(RUNTIME_CLASS(CFrameWnd))<<"\n\n"; //为false
cout<<pMyWnd->IsKindOf(RUNTIME_CLASS(CFrameWnd))<<"\n"; //为true
cout<<pMyWnd->IsKindOf(RUNTIME_CLASS(CWnd))<<"\n"; //为true
cout<<pMyWnd->IsKindOf(RUNTIME_CLASS(CObject))<<"\n"; //为true
cout<<"pMyWnd->IsKindOf(RUNTIME_CLASS(CDocument))<<"\n"; //为false
详细代码,请看工程Frame4。
效果如下:
图(2)“类型识别”的结果
//mfc.h
#define BOOL int #define TRUE 1 #define FALSE 0 #define LPCSTR LPSTR typedef char* LPSTR; #define UINT int #define PASCAL _stdcall #include <iostream.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; // 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 _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) class CObject { public: CObject::CObject() { } CObject::~CObject() { } virtual CRuntimeClass* GetRuntimeClass() const; BOOL IsKindOf(const CRuntimeClass* pClass) const; public: static CRuntimeClass classCObject; }; 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_DYNAMIC(CWnd) public: CWnd::CWnd() { } CWnd::~CWnd() { } virtual BOOL Create(); BOOL CreateEx(); virtual BOOL PreCreateWindow(); }; class CFrameWnd : public CWnd { DECLARE_DYNAMIC(CFrameWnd) public: CFrameWnd::CFrameWnd() { } CFrameWnd::~CFrameWnd() { } BOOL Create(); virtual BOOL PreCreateWindow(); }; class CView : public CWnd { DECLARE_DYNAMIC(CView) public: CView::CView() { } CView::~CView() { } }; // global function CWinApp* AfxGetApp();
#include "my.h" 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; } 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; } 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; } IMPLEMENT_DYNAMIC(CCmdTarget,CObject) IMPLEMENT_DYNAMIC(CWinThread,CCmdTarget) IMPLEMENT_DYNAMIC(CWinApp,CWinThread) IMPLEMENT_DYNAMIC(CWnd,CCmdTarget) //其实在MFC中此句是,IMPLEMENT_DYNCREATE() IMPLEMENT_DYNAMIC(CFrameWnd,CWnd) //其实在MFC中此句是,IMPLEMENT_DYNCREATE() IMPLEMENT_DYNAMIC(CDocument,CCmdTarget) IMPLEMENT_DYNAMIC(CView,CWnd) //global function CWinApp* AfxGetApp() { 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_DYNAMIC(CMyFrameWnd) public: CMyFrameWnd(); ~CMyFrameWnd(){} }; class CMyDoc:public CDocument { DECLARE_DYNAMIC(CMyDoc) public: CMyDoc::CMyDoc(){} CMyDoc::~CMyDoc(){} }; class CMyView:public CView { DECLARE_DYNAMIC(CMyView) public: CMyView::CMyView(){} CMyView::~CMyView(){} }; //global function void PrintAllClasses();
//my.cpp
#include "my.h" CMyWinApp theApp; BOOL CMyWinApp::InitInstance() { m_pMainWnd = new CMyFrameWnd; return TRUE; } CMyFrameWnd::CMyFrameWnd() { Create(); } //宏的实现 IMPLEMENT_DYNAMIC(CMyFrameWnd,CFrameWnd) //在MFC中,此语句是,IMPLEMENT_DYNCREATE(CMyFrameWnd,CFrameWnd) IMPLEMENT_DYNAMIC(CMyDoc,CDocument) //在MFC中,此语句是,IMPLEMENT_DYNCREATE(CMyDoc,CDocument) IMPLEMENT_DYNAMIC(CMyView,CView) //在MFC中,此语句是,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"; } } void main() { CWinApp* pApp = AfxGetApp(); pApp->InitApplication(); pApp->InitInstance(); pApp->Run(); //PrintAllClasses(); CMyDoc* pMyDoc = new CMyDoc; CMyView* pMyView = new CMyView; CWnd* pMyWnd = pApp->m_pMainWnd; cout<<"pMyDoc->IsKindOf(RUNTIME_CLASS(CMyDoc)) "<<pMyDoc->IsKindOf(RUNTIME_CLASS(CMyDoc))<<"\n"; cout<<"pMyDoc->IsKindOf(RUNTIME_CLASS(CDocument)) "<<pMyDoc->IsKindOf(RUNTIME_CLASS(CDocument))<<"\n"; cout<<"pMyDoc->IsKindOf(RUNTIME_CLASS(CCmdTarget)) "<<pMyDoc->IsKindOf(RUNTIME_CLASS(CCmdTarget))<<"\n"; cout<<"pMyDoc->IsKindOf(RUNTIME_CLASS(CObject)) "<<pMyDoc->IsKindOf(RUNTIME_CLASS(CObject))<<"\n"; cout<<"pMyDoc->IsKindOf(RUNTIME_CLASS(CWinApp)) "<<pMyDoc->IsKindOf(RUNTIME_CLASS(CWinApp))<<"\n"; cout<<"pMyDoc->IsKindOf(RUNTIME_CLASS(CView)) "<<pMyDoc->IsKindOf(RUNTIME_CLASS(CView))<<"\n\n"; cout<<"pMyView->IsKindOf(RUNTIME_CLASS(CView)) "<<pMyView->IsKindOf(RUNTIME_CLASS(CView))<<"\n"; cout<<"pMyView->IsKindOf(RUNTIME_CLASS(CObject)) "<<pMyView->IsKindOf(RUNTIME_CLASS(CObject))<<"\n"; cout<<"pMyView->IsKindOf(RUNTIME_CLASS(CWnd)) "<<pMyView->IsKindOf(RUNTIME_CLASS(CWnd))<<"\n"; cout<<"pMyView->IsKindOf(RUNTIME_CLASS(CFrameWnd)) "<<pMyView->IsKindOf(RUNTIME_CLASS(CFrameWnd))<<"\n\n"; cout<<"pMyWnd->IsKindOf(RUNTIME_CLASS(CFrameWnd)) "<<pMyWnd->IsKindOf(RUNTIME_CLASS(CFrameWnd))<<"\n"; cout<<"pMyWnd->IsKindOf(RUNTIME_CLASS(CWnd)) "<<pMyWnd->IsKindOf(RUNTIME_CLASS(CWnd))<<"\n"; cout<<"pMyWnd->IsKindOf(RUNTIME_CLASS(CObject)) "<<pMyWnd->IsKindOf(RUNTIME_CLASS(CObject))<<"\n"; cout<<"pMyWnd->IsKindOf(RUNTIME_CLASS(CDocument)) "<<pMyWnd->IsKindOf(RUNTIME_CLASS(CDocument))<<"\n"; }