Run-Time Type Information/RTTI

Run-Time Type Information is a property to identify the name or type of an object at runtime. C++ object usually do not contain type information. Run-Time Type Information is the name or type in the class. This helps to idetify the type as well as the hierarchil parent child relationship.

Run-Time Type Information is essential for client server applications where clients connect to server and passes object pointer to server. Server and clients are decoupled and developed seperately. Server should examine the objects provided by clients before processing them. Client can pass any type of object at runtime. Server sould examine Run-Time Type Information to check the type and the parent type if it is devived correctly. Object pointer contain a correct memory layout, size and vTable pointer when it is derived correctly otherwise server may crash while accessing members or calling virtual functions. Server should throw error to client if correct object is not provided. Hence Run-Time Type Information (RTTI) support s essential and introduced in MFC introduced in MFC 4.0.

RTTI macros

An MFC object should be able to hold RTTI information if the type class is derived from CObject and following of the macro pair is used in declaration and definition.

  1. DECLARE_DYNAMIC and IMPLEMENT_DYNAMIC,
  2. DECLARE_DYNCREATE and IMPLEMENT_DYNCREATE,
  3. DECLARE_SERIAL and IMPLEMENT_SERIAL

RTTI demo object validation

class CUnknownObj : public CObject
{
  DECLARE_DYNAMIC(CUnknownObj)
};
IMPLEMENT_DYNAMIC( CUnknownObj, CObject )

class CDrawObj : public CObject
{
  virtual void Draw(void) = 0;
  DECLARE_DYNAMIC(CDrawObj)
};
IMPLEMENT_DYNAMIC( CDrawObj, CObject )

class CRectangle : public CDrawObj
{
  virtual void Draw(void);
  DECLARE_DYNAMIC(CRectangle)
};
IMPLEMENT_DYNAMIC( CRectangle, CDrawObj )
void CRectangle::Draw(void)
{
  cout << "Draw Rect";
}

class CCircle : public CDrawObj
{
  virtual void Draw(void);
  DECLARE_DYNAMIC(CCircle)
};
IMPLEMENT_DYNAMIC( CCircle, CDrawObj )
void CCircle::Draw(void)
{
	cout << "Draw Circle";
}

/* Client side code */
CObject *GetObjectFromUser(char *ClassName)
{
	if(strcmp(ClassName, "CRectangle") == 0) 
	return new CRectangle();
	else  if(strcmp(ClassName, "CCircle") == 0)
	return new CCircle();
	else  if(strcmp(ClassName, "CUnknown") == 0)
	return new CUnknownObj;

}

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
	int nRetCode = 0;

	// initialize MFC and print and error on failure
	if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
	{
		// TODO: change error code to suit your needs
		cerr << _T("Fatal Error: MFC initialization failed") << endl;
		nRetCode = 1;
	}
	else
	{
		cout << "Server side object validation " << endl;

		/* Validate CRectangle object */
		CObject *obj = GetObjectFromUser("CRectangle");
		// TODO: code your application's behavior here.
		cout << "CRectangle is IsKindOf " << endl;
		if(obj->IsKindOf(RUNTIME_CLASS(CObject))!=0)
			cout <<"CObject " << endl;
		if(obj->IsKindOf(RUNTIME_CLASS(CDrawObj))!=0)
			cout <<"CDrawObj " << endl;
		if(obj->IsKindOf(RUNTIME_CLASS(CRectangle))!=0)
			cout <<"CRectangle " << endl;
		if(obj->IsKindOf(RUNTIME_CLASS(CCircle))!=0)
			cout <<"CCircle " << endl;

		cout << endl;

		/* Validate CCircle object */
		CObject *obj1 = GetObjectFromUser("CCircle");
		cout << "CCircle is IsKindOf "<< endl;
		if(obj1->IsKindOf(RUNTIME_CLASS(CObject))!=0)
			cout <<"CObject " << endl;
		if(obj1->IsKindOf(RUNTIME_CLASS(CDrawObj))!=0)
			cout <<"CDrawObj " << endl;
		if(obj1->IsKindOf(RUNTIME_CLASS(CRectangle))!=0)
			cout <<"CRectangle " << endl;
		if(obj1->IsKindOf(RUNTIME_CLASS(CCircle))!=0)
			cout <<"CCircle " << endl;

		cout << endl;

		/* Validate CUnknown object */
		CObject *obj2 = GetObjectFromUser("CUnknown");
		cout << "CUnknown is IsKindOf "<< endl;
		if(obj2->IsKindOf(RUNTIME_CLASS(CObject))!=0)
			cout <<"CObject " << endl;
		if(obj2->IsKindOf(RUNTIME_CLASS(CDrawObj))!=0)
			cout <<"CDrawObj " << endl;
		if(obj2->IsKindOf(RUNTIME_CLASS(CRectangle))!=0)
			cout <<"CRectangle " << endl;
		if(obj2->IsKindOf(RUNTIME_CLASS(CCircle))!=0)
			cout <<"CCircle " << endl;
	}

	return nRetCode;
}

Program output

Server side object validation
CRectangle is IsKindOf
CObject
CDrawObj
CRectangle

CCircle is IsKindOf
CObject
CDrawObj
CCircle

CUnknown is IsKindOf
CObject
Press any key to continue

About our authors: Team EQA

Further readings

Where is WinMain() function in MFC application ?

MFC hides WinMain in its framework and includes source file on WinMain(). This explains how framework calls global CWinApp::Initinstance() from entry WinMain.

What is the utility of CWinApp class?

This is constructed during global C++ objects are constructed and is already available when Windows calls the WinMain function, which is supplied by the ...

Basic steps in Win32 GUI Application with source code.

Define a custom Window class structure, Register the class name, CreateWindow, Show windows and write message get and dispatch loop statements. Define the Window CallBack procedure and write the handlers.

What is a Window CallBack procedure and what is its utility?

DispatchMessage() is a API which indirectly triggers the Window CallBack procedure. Message structure members from this function are passed to the CallBack procedure. CallBack procedure should implement event handlers depending on the need of the application.

What are LPARAM and WPARAM in window proc function?

LPARAM and WPARAM are the two parameters in Window CallBack procedure. They signifies parameters of various events. They are used in handing individual events.

What are the basic steps of a typical MFC based application?

We need to write WinMain and need to follow all these in a Win32 application. However we need not to write much if we are writing an application with MFC ...

#