Kernel SDK Developer's Guide > Run-Time Type Identification > Implementing RTTI Methods for the Derived Class
Implementing RTTI Methods for the Derived Class

When you derive a class from the OdRxObject abstract class, you either use the OdRxObjectImpl template class or the OdStaticRxObject template class to implement the reference counting and transform an abstract class into a real class. For example:

class xSomeObj : public OdRxObjectImpl<OdRxObject>
{
 public:
   xSomeObj();
   ~xSomeObj();
};

But these template classes do not create the implementation of RTTI methods. The basic RTTI functionality is only declared in the OdRxObject class. Each class derived from the OdRxObject class must redefine the RTTI methods in itself. To redefine the RTTI methods, use the ODRX_DECLARE_MEMBERS macro to redefine the following standard RTTI members for your derived class:

  • g_pDesc static member — The raw pointer to the class describing structure.
  • cast() static method — Casts the specified raw pointer to the smart pointer of the derived class.
  • desc() static method — Returns the raw pointer to the class describing instance.
  • isA() virtual method — Returns the raw pointer to the class describing instance.
  • queryX() virtual method — Checks whether the instance belongs to the class being defined.
  • pseudoConstructor() static method — Creates a new instance of the derived class.
  • createObject() static method — Creates a new instance of the derived class.
  • rxInit() static method — Registers the derived class in the application.
  • rxUninit() static method — Unregisters the derived class in the application.

The cast() and createObject() method are inline methods and this macro creates their implementation automatically. You must use the ODRX_DECLARE_MEMBERS macro in the "public:" section of the class definition syntactic construct when you derive own class.

class xSomeObj : public OdRxObjectImpl<OdRxObject>
{
 public:
   ODRX_DECLARE_MEMBERS(xSomeObj);

   xSomeObj();
   ~xSomeObj();
};

If you set the "Generate Preprocessed File" (option /P /EP) in your project properties and compile the source file with this class declaration, the result of the macro substitution is seen in the I-file. This macro will be transformed in the following lines:

class xSomeObj : public OdRxObjectImpl<OdRxObject>
{
 public:
   static OdRxClass* g_pDesc; 
   static OdRxClass* desc(); 
   virtual OdRxClass* isA() const; 
   virtual OdRxObject* queryX(const OdRxClass* protocolClass) const; 
   static OdRxObjectPtr pseudoConstructor(); 
   static OdSmartPtr<xSomeObj> createObject() 
          { 
             if (!desc()) throw OdError(eNotInitializedYet); 
             return desc()->create(); 
          } 
   static OdSmartPtr<xSomeObj> cast(const OdRxObject* pObj) 
          {   
             if (pObj) return OdSmartPtr<xSomeObj>(((xSomeObj*)pObj->queryX(xSomeObj::desc())), kOdRxObjAttach); 
             return (xSomeObj*)0; 
          } 
   static void rxInit(); 
   static void rxInit(AppNameChangeFuncPtr m_appNameChangeFunc); 
   static void rxUninit();
 
   xSomeObj();
   ~xSomeObj();
};

After declaration, create the implementation of the RTTI methods in your own CPP-modules using the following macros:

  • ODRX_DEFINE_RTTI_MEMBERS — Creates the default implementation of the desc(), isA(), and queryX() methods and requires the class name and parent class name.
  • ODRX_DEFINE_INIT_MEMBERS — Creates the default implementation of the rxInit() and rxUninit() methods and requires the class name, parent class name, pseudo-constructor function name, .dwg file version, maintenance version, proxy flags, dwg class name, dxf class name, application class name, and custom flags.
  • ODRX_DEFINE_PSEUDOCONSTRUCTOR — Creates the default implementation of the pseudoConstructor() method and requires the class name and pseudo-constructor substituting macro name that generates the implementing code.
  • ODRX_DEFINE_MEMBERS — Creates the default implementation of all RTTI methods using the ODRX_DEFINE_RTTI_MEMBERS, ODRX_DEFINE_INIT_MEMBERS, and ODRX_DEFINE_PSEUDOCONSTRUCTOR macros and requires the class name, parent class name, pseudo-constructor substituting macro name, .dwg file version number, maintenance version number, proxy flags, dwg class name, dxf class name, application class name, and custom flags.
  • ODRX_DEFINE_MEMBERS2 — Creates the default implementation of RTTI methods analogically using the ODRX_DEFINE_MEMBERS macro, but it does not create an implementation of a pseudo-constructor (you must implement your own pseudo-constructor).
  • ODRX_NO_CONS_DEFINE_MEMBERS — Creates the default implementation of RTTI methods with specified class name, specified parent class name, empty pseudo-constructor, zero version numbers, zero proxy flags, zero custom flags, empty dxf and application names, dwg class name coinciding with the class name, and uses the ODRX_DEFINE_MEMBERS2 macro. To implement the empty pseudo-constructor, it uses the EMPTY_CONSTR substituting macro. It requires the class name and parent class name.
  • ODRX_NO_CONS_DEFINE_MEMBERS_ALTNAME — Creates the default implementation of RTTI methods analogically using the ODRX_NO_CONS_DEFINE_MEMBERS macro, but allows you specify an alternate dwg class name.
  • ODRX_CONS_DEFINE_MEMBERS — Creates the default implementation of RTTI methods with specified class name, specified parent class name, zero version numbers, zero proxy flags, zero custom flags, empty dxf and application names, dwg class name coinciding with the class name, and uses the ODRX_DEFINE_MEMBERS2 macro. This macro implements the pseudo-constructor using the ODRX_DEFINE_PSEUDOCONSTRUCTOR macro and the NEWOBJ_CONSTR, RXIMPL_CONSTR, or user-defined pseudo-constructor substituting macro. It requires the class name, parent class name, and substituting macro name.
  • ODRX_CONS_DEFINE_MEMBERS_ALTNAME — Creates the default implementation of RTTI methods analogically using the ODRX_CONS_DEFINE_MEMBERS macro, but it allows you to specify an alternate dwg class name.
  • ODRX_DXF_DEFINE_MEMBERS — Creates the default implementation of RTTI methods with specified version numbers, proxy flags, dxf name, application name, class name, parent class name, and user-defined pseudo-constructor substituting macro. All information is required.
  • ODRX_DXF_CONS_DEFINE_MEMBERS — Creates the default implementation of RTTI methods with specified version numbers, proxy flags, dxf name, application name, class name, parent class name, but implements the default pseudo-constructor using the NEWOBJ_CONSTR substituting macro and generates the dwg class name coinciding with the class name.

The ODRX_DEFINE_RTTI_MEMBERS, ODRX_DEFINE_INIT_MEMBERS, ODRX_DEFINE_PSEUDOCONSTRUCTOR, and ODRX_DEFINE_MEMBERS2 macros are usually used as auxiliary macros. TheODRX_DEFINE_MEMBERS and ODRX_DXF_DEFINE_MEMBERS macros are used when all RTTI information must be specified for the derived class. The ODRX_NO_CONS_DEFINE_MEMBERS, ODRX_CONS_DEFINE_MEMBERS, and ODRX_DXF_CONS_DEFINE_MEMBERS macros are generally used.

For macros requiring a pseudo-constructor, use the EMPTY_CONSTR, NEWOBJ_CONSTR, and RXIMPL_CONSTR substituting macros defined in the header files to generate the code to implement the pseudo-constructor. The EMPTY_CONSTR substituting macro generates the empty pseudo-constructor casting a null pointer. The NEWOBJ_CONSTR substituting macro generates the pseudo-constructor that creates a new instance of the specified class, creates a smart pointer to it, does not increment its reference counter, and returns the smart pointer to the instance. The RXIMPL_CONSTR substituting macro generates the pseudo-constructor that creates a new instance of the specified class using the createObject() static method of this class and wraps it using the OdRxObjectImpl template. These substituting macros have the following implementation:

#define EMPTY_CONSTR(ClassName)   (ClassName*)0
#define NEWOBJ_CONSTR(ClassName)  OdSmartPtr<ClassName>(new ClassName, kOdRxObjAttach)
#define RXIMPL_CONSTR(ClassName)  OdRxObjectImpl<ClassName>::createObject()

You can define your own substituting macro when the creating of an instance is not complicated for your class.

To create the standard implementation of RTTI methods, pass the ODRX_CONS_DEFINE_MEMBERS macro in the cpp-module:

ODRX_CONS_DEFINE_MEMBERS(xSomeObj, OdRxObject, NEWOBJ_CONSTR);

To create the implementation with the empty pseudo-constructor, pass the ODRX_NO_CONS_DEFINE_MEMBERS macro in the cpp-module:

ODRX_NO_CONS_DEFINE_MEMBERS(xSomeObj, OdRxObject);

To create the standard implementation and redefine all information, pass the ODRX_DEFINE_MEMBERS macro in the cpp-module:

ODRX_DEFINE_MEMBERS(xSomeObj, OdRxObject, RXIMPL_CONSTR, 3, 2, 36, "MyRxClass", "acMYCLASS", "MyApp");

If you set the "Generate Preprocessed File" (option /P /EP) in your project properties and compile the cpp-file, the result of the substitution for these macros is seen in the I-file. The ODRX_CONS_DEFINE_MEMBERS macro will be transformed in the following lines:

OdRxClass* xSomeObj::g_pDesc = 0; 
OdRxClass* xSomeObj::desc() {  return g_pDesc;  } 
OdRxClass* xSomeObj::isA() const { return g_pDesc;  } 

OdRxObject* xSomeObj::queryX(const OdRxClass* pClass) const 
{ 
  return ::odQueryXImpl<xSomeObj,OdRxObject>(this, pClass); 
} 
void xSomeObj::rxUninit() 
{
  if(xSomeObj::g_pDesc) 
  { 
    ::deleteOdRxClass(xSomeObj::g_pDesc); 
    xSomeObj::g_pDesc = 0; 
  } 
  else {  throw OdError(eNotInitializedYet);  } 
} 
void xSomeObj::rxInit() 
{
  if(!xSomeObj::g_pDesc) 
  {   xSomeObj::g_pDesc = ::newOdRxClass( ((const OdChar*)L"xSomeObj"), OdRxObject::desc(), 
                                          xSomeObj::pseudoConstructor, 0, 0, 0, OdString::kEmpty, OdString::kEmpty, NULL, 0 );  } 
  else {  throw OdError(eExtendedError);  } 
}
void ClassName::rxInit(AppNameChangeFuncPtr pAppNameChangeCallback)                                  
{                                                                                                    
  if(!xSomeObj::g_pDesc) {                                                                         
    xSomeObj::g_pDesc = ::newOdRxClass( ((const OdChar*)L"xSomeObj"), OdRxObject::desc(),                          
                                          xSomeObj::pseudoConstructor, 0, 0, 0, OdString::kEmpty, OdString::kEmpty, pAppNameChangeCallback, 0); 
  } else { throw OdError(eExtendedError);  }
}
OdRxObjectPtr xSomeObj::pseudoConstructor() 
{ 
  return OdRxObjectPtr(OdSmartPtr<xSomeObj>(new xSomeObj, kOdRxObjAttach)); 
}

The result of transforming the ODRX_NO_CONS_DEFINE_MEMBERS macro will differ only by implementation of the pseudoConstrutor() and rxInit() methods and will have the following lines:

void xSomeObj::rxInit() 
{
  if(!xSomeObj::g_pDesc) 
  {   xSomeObj::g_pDesc = ::newOdRxClass( ((const OdChar*)L"xSomeObj"), OdRxObject::desc(), 
                                          0, 0, 0, 0, OdString::kEmpty, OdString::kEmpty, NULL, 0);  } 
  else {  throw OdError(eExtendedError); } 
} 
OdRxObjectPtr xSomeObj::pseudoConstructor() {  return OdRxObjectPtr((xSomeObj*)0);  }

The result of transforming the ODRX_NO_CONS_DEFINE_MEMBERS macro will differ by implementation of the pseudoConstrutor() and rxInit() methods and will have the following lines:

void xSomeObj::rxInit() 
{
  if(!xSomeObj::g_pDesc) 
  {   xSomeObj::g_pDesc = ::newOdRxClass( "MyRxClass", OdRxObject::desc(), 
                                          xSomeObj::pseudoConstructor, 3, 2, 36, "acMYCLASS", "MyApp", NULL, 0);  } 
  else {  throw OdError(eExtendedError);  } 
} 
OdRxObjectPtr xSomeObj::pseudoConstructor() {  return OdRxObjectPtr(OdRxObjectImpl<xSomeObj>::createObject());  }

All macros use the newOdRxClass() global function for registering the derived class and the deleteOdRxClass() global function for unregistering the derived class in these implementations. The first and second macros pass zero version numbers, zero proxy flags, empty dxf and application names, and the third macro passes all specified parameters.

See Also

RTTI Technology

Understanding Pseudo-Constructors

Implementing the Class Describing Structure

Registering and Unregistering Classes in a Program

Belonging to an Instance of a Class

Copyright © 2002 – 2020. Open Design Alliance. All rights reserved.