MFC中的运行时类型识别(RTTI)

RTTI是Runtime Type Identification的缩写,中文名为“运行时类型识别”。

MFC早在编译器支持RTTI之前,就有了这种能力。我们现在要以相同的手法,在Console程序中仿真出来。我希望我的类库具备IsKindOf 的能力,能在执行期侦测到某个对象是否属于某个类,并传回TRUE 或 FALSE。以形状 Shape为例 ,我希望:

即 长方形属于“长方形类”,正方形属于“长方形类”,圆不属于“长方形类”,原因是长方形派生 正方形类。

CMyDoc 属于“CMyDoc类”,CMyDoc也属于“CDocument类”,CMyDoc也属于“CCmdTarget类” ,CMyDoc不属于“CWnd类” 。原因是CCmdTarget派生CDocument类,CDocument
派生 CMyDoc类。

同时,我希望,每一个类都能拥有这样一个CRuntimeClass 成员变量,并且最后有一定的命名规则(例如,在类名称之前冠以“class”作为它的名称),然后,经由某种手段将整个类库构建好之后,“类别型录”就能呈现如下图(2)所示的面貌:

图(2)“类别型录”的链表形式

下面,以控制台应用程序Frame3为例,模拟mfc的RTTI功能。

在案例Frame3 的cpp 文件中,有这样的操作:

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)

于是,组织出如图(3-1)所示的一张大网:

为了证明,程序中存在整个“类别型录网”。我在main函数中调用 PrintAllClasses ,把链表中的每一个元素的类名称、对象大小,以及scheme.no,打印出来。

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";
	}
}

效果如下:

图(4)链表中的每一个元素的类名称、对象大小,以及scheme.no,说明存在该“类别型录网”

详细代码如下:

//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;

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();

//mfc.cpp

#include "my.h"

CMyWinApp theApp;

BOOL CMyWinApp::InitInstance()
{
	m_pMainWnd = new CMyFrameWnd;
	return TRUE;
}

CMyFrameWnd::CMyFrameWnd()
{
	Create();
}

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();
}

//my.h

#include <iostream.h>
#include "mfc.h"

class CMyWinApp:public CWinApp
{
public:
	CMyWinApp::CMyWinApp(){}
	CMyWinApp::~CMyWinApp(){}

	virtual BOOL InitInstance();
};

class CMyFrameWnd:public CFrameWnd
{
public:
	CMyFrameWnd();
	~CMyFrameWnd(){}
};

class CMyDoc:public CDocument
{
public:
	CMyDoc::CMyDoc(){}
	CMyDoc::~CMyDoc(){}
};

class CMyView:public CView
{
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();
}

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();
}
时间: 2024-10-05 05:13:46

MFC中的运行时类型识别(RTTI)的相关文章

C++运行时类型识别——RTTI

RTTI 通过运行时类型识别--RTTI,程序能够使用基类的指针或引用来检索这些指针或引用所指对象的实际派生类类型: 其主要通过两个操作符来实现: 1.typeid--返回指针或引用所指对象的实际类型: 2.dynamic_cast--将基类类型的指针或引用安全地转换为派生类型的指针或引用: dynamic_cast 当无法为基类增加虚函数,又要使用基类的指针或引用调用派生类的函数时,可以使用该操作符代替虚函数. 与dynamic_cast一起使用的指针必须是有效的--它必须为0或者指向一个对象

C++学习之显示类型转换与运行时类型识别RTTI

static_cast const_cast reinterpret_cast 运行时类型识别(RTTI) dynamic_cast 哪种情况下dynamic_cast和static_cast使用的情况一样? 什么情况下使用dynamic_cast代替虚函数? typeid 命名的强制类型转换形式如下: cast_name<type>(expression); 其中:cast_name指static_cast.dynamic_cast.const_cast.reinterpret_cast中的

运行时类型识别RTTI

1.RTTI的工作原理 例1. 用Class加载对象示例. package RTTI; public class Candy { static{ System.out.println("Loading Candy in static block."); } public static void main(String[] args) { System.out.println("Loading Candy in main method."); } } package

Java基础之RTTI 运行时类型识别

运行时类型识别(RTTI, Run-Time Type Identification)是Java中非常有用的机制,在Java运行时,RTTI维护类的相关信息. 多态(polymorphism)是基于RTTI实现的.RTTI的功能主要是由Class类实现的. Class类 Class类是"类的类"(class of classes).如果说类是对象的抽象和集合的话,那么Class类就是对类的抽象和集合. 每一个Class类的对象代表一个其他的类.比如下面的程序中,Class类的对象c1代

运行时类型识别

1.RTTI 1)运行时类型识别RTTI(Run-Time Type Identification),它能够获取基类指针或引用所指向的对象的实际类型,在C++中,为了支持RTTI提供了两个运算符:typeid和dynamic_cast 2) 2.dynamic_cast 2.1概念 1)dynamic_cast运算符用于将基类的指针或引用安全地转换成派生类的指针或引用,这是安全的“向下转型”,至于“向上转型”,即派生类指针或引用转换为其基类指针或引用,本身就是安全的,尽管可以使用dynamic_

MFC 六大机制 (2) RTTI(运行时类型识别)

RTTI(Runtime Type Identification,运行时类型识别) 程序能够使用基类的指针或引用来检查这些指针或引用所指的对象的实际派生类型.MFC 早在编译器支持 RTTI 之前,就具有了这项能力.承接上一章,我们现在要在 Console 程序中将 RTTI 仿真出来.我希望我的类库具备 IsKindOf() 的能力,能够在执行器检查某个对象是否"属于某种类",并传回 TRUE 或 FALSE.为了更直观地查看结果,我在 IsKindOf() 中加入了输出,使其达到如

MFC六大核心机制之二:运行时类型识别(RTTI)

上一节讲的是MFC六大核心机制之一:MFC程序的初始化,本节继续讲解MFC六大核心机制之二:运行时类型识别(RTTI). typeid运算子 运行时类型识别(RTTI)即是程序执行过程中知道某个对象属于某个类,我们平时用C++编程接触的RTTI一般是编译器的RTTI,即是在新版本的VC++编译器里面选用“使能RTTI”,然后载入typeinfo.h文件,就可以使用一个叫typeid()的运算子,它的地位与在C++编程中的sizeof()运算子类似的地方(包含一个头文件,然后就有一个熟悉好用的函数

RTTI (Run-Time Type Identification,通过运行时类型识别) 转

参考一: RTTI(Run-Time Type Identification,通过运行时类型识别)程序能够使用基类的指针或引用来检查这些指针或引用所指的对象的实际派生类型. RTTI提供了以下两个非常有用的操作符: (1)typeid操作符,返回指针和引用所指的实际类型: (2)dynamic_cast操作符,将基类类型的指针或引用安全地转换为派生类型的指针或引用. 面向对象的编程语言,象C++,Java,delphi都提供了对RTTI的支持. 本文将简略介绍 RTTI 的一些背景知识.描述 R

RTTI 运行时类型识别

RTTI   运行时类型识别 typeid  ------  dynamic_cast dynamic_cast 注意事项: 1.只能应用于指针和引用之间的转化 2.要转换的类型中必须包含虚函数 3.转换成功返回的是子类的地址,失败返回NULL typeid注意事项: 1.typeid返回一个type_info对象的引用 2.如果想通过基类获得派生类的数据类型,基类必须带有虚函数 3.只能获取对象的实际类型