Kernel SDK Developer's Guide > Run-Time Type Identification > Functionality of Pseudo-Constructors
Functionality of Pseudo-Constructors

The OdRxClass class and OdRxObject class provide the ability to create dynamic instances using pseudo-constructors. The base OdRxObject class declares the protected (new) and (delete) operations that do not allow creating of instances for derived classes using the (new) operation directly. Instead of standard operations, the OdRxClass class declares the create() public virtual method, and the OdRxObject class declares the pseudoConstructor() public static method and the createObject() public static method that create new instances of classes derived from the OdRxObject class. Therefore, the creation of instances becomes a protected operation that must be performed by methods of the class. The ODRX_DECLARE_MEMBERS macro and  ODRX_**_DEFINE_MEMBERS_** macros generate the cpp-code for these methods and provide the automatic implementation of pseudo-constructors.

For example, an xMajorCls class is derived from the OdRxObject class and has the following definition:

class xMajorCls : public OdRxObjectImpl<OdRxObject>
{
 public:
   ODRX_DECLARE_MEMBERS(xMajorCls);                                  // Declaring the RTTI methods
   xMajorCls() {};
   ~xMajorCls() {};
};
typedef OdSmartPtr<xMajorCls> xMajorClsPtr;                         

ODRX_DEFINE_MEMBERS(xMajorCls, OdRxObject, NEWOBJ_CONSTR);           // Implementing the RTTI methods

The xMajorCls class must be registered in the program using the rxInit() static method before applying the RTTI methods and pseudo-constructors. If a class is not registered, the RTTI methods generate the eNotApplicable exception. To get the class describing instance, use the desc() static method that returns the smart pointer of the OdRxClass type referring to the class describing instance statically associated with this registered class.

#include "OdaCommon.h"
#include "OdToolKit.h"
#include "..\..\Teigha.dwg\Extensions\ExServices\ExHostAppServices.h"
#include "..\..\Teigha.dwg\Extensions\ExServices\ExSystemServices.h"

class MyApp : public ExSystemServices 
{
 protected:
   ODRX_USING_HEAP_OPERATORS(ExSystemServices);
   MyApp() {};
};

void main()
{
   OdStaticRxObject<MyApp> svcs;
   odInitialize(&svcs);
   xMajorCls::rxInit();                                              // Registering the class
	
   OdRxClassPtr pCls = xMajorCls::desc();                            // Getting the class describing instance

   odPrintConsoleString(L"\nThe substituting class describing instance = %x \"%s\"", pCls.get(), pCls->name().c_str());

   // Prints: The substituting class describing instance = 14A208 "xMajorCls"
   // Here, past a one of cpp-codes described below 
	
   xMajorCls::rxUninit();                                            // Unregistering the class
   odUninitialize();
}	

To create a new instance of the xMajorCls class, use the create() method declared by the OdRxClass class that creates a new instance using the dynamic pseudo-constructor specified by the m_pConstr member of the class describing instance and returns the non-typified smart pointer to the created instance. For example:

OdRxObjectPtr pInst1 = pCls->create();

odPrintConsoleString(L"\nInstance 1 = %x , Class = %s [%x]", pInst1.get(), pInst1->isA()->name().c_str(), pInst1->isA());
                                              
// Prints: Instance 1 = 13A048 , Class = xMajorCls [14A208]

A new instance can be also created by the createObject() static method of the xMajorCls class which is the pseudo-constructor automatically generated by the ODRX_DECLARE_MEMBERS macro for this class. The createObject() method creates a new instance using the create() method of the class describing instance that is statically associated with this class and returns the typified smart pointer to the created instance. For example:

xMajorClsPtr pInst2 = xMajorCls::createObject();

odPrintConsoleString(L"\nInstance 2 = %x , Class = %s [%x]", pInst2.get(), pInst2->isA()->name().c_str(), pInst2->isA()); 

// Prints:  Instance 2 = 13A258 , Class = xMajorCls [14A208]

A new instance can also be created by the pseudoConstructor() static method of the xMajorCls class that is the static default pseudo-constructor automatically generated by the ODRX_DEFINE_PSEUDOCONSTRUCTOR macro for this class. The pseudoConstructor() creates a new instance using the cpp-code generated by the macro and returns the non-typified smart pointer to the created instance. For example:

OdRxObjectPtr pInst3 = xMajorCls::pseudoConstructor();

odPrintConsoleString(L"\nInstance 3 = %x , Class = %s [%x]", pInst3.get(), pInst3->isA()->name().c_str(), pInst3->isA()); 

// Prints:  Instance 3 = 13A368 , Class = xMajorCls [14A208]

A new instance can be also created by the odrxCreateObject() global function that uses the class dictionary and class name for finding the class describing instance, creates a new instance of the registered class using the create() method of the found class describing instance, and returns the non-typified smart pointer to the created instance or NULL if the class is not registered. For example:

OdRxObjectPtr pInst4 = odrxCreateObject(L"xMajorCls");

odPrintConsoleString(L"\nInstance 4 = %x , Class = %s [%x]", pInst4.get(), pInst4->isA()->name().c_str(), pInst4->isA()); 

// Prints:  Instance 4 = 13A478 , Class = xMajorCls [14A208]

To get the pseudo-constructor, use the constructor() method of the class describing instance, which returns the pointer to the creating function of the OdPseudoConstructorType type that is the pseudo-constructor for this class. For example:

OdPseudoConstructorType pCnstr = pCls->constructor();

odPrintConsoleString(L"\nThe constructor address = %x", pCnstr);      // Prints:  = 1B0817

The obtained pointer can be used to create instances for the class. For example:

OdRxObjectPtr pInst5 = (pCnstr)();
OdRxObjectPtr pInst6 = (pCnstr)();

odPrintConsoleString(L"\nInstance 5 = %x , Class = %s [%x]", pInst5.get(), pInst5->isA()->name().c_str(), pInst5->isA());
odPrintConsoleString(L"\nInstance 6 = %x , Class = %s [%x]", pInst6.get(), pInst6->isA()->name().c_str(), pInst6->isA());

// Prints:  Instance 5 = 13A588 , Class = xMajorCls [14A208]
// Prints:  Instance 6 = 13A698 , Class = xMajorCls [14A208]

To modify the pseudo-constructor, use the setConstructor() method of the class describing instance, which requires the pointer to the creating function as an argument of the OdPseudoConstructorType type and does not return a value. The creating function must be defined before applying it. An alternate creating function can be the pseudo-constructor of another class that substitutes the defined class when it creates its own instances. The substituting class can expand the functionality of the defined class. For example, declare the following substituting class:

class xSubstitutingCls : public OdRxObjectImpl<OdRxObject>
{
 public:
   ODRX_DECLARE_MEMBERS(xSubstitutingCls);                           // Declaring of the RTTI methods
   xSubstitutingCls() {};
   ~xSubstitutingCls() {};
};                                                                   // Implementing of the RTTI methods

ODRX_CONS_DEFINE_MEMBERS(xSubstitutingCls, OdRxObject, NEWOBJ_CONSTR);

The substituting class must be registered. As a result, it will be associated with its own class describing instance that will contain the own pseudo-constructor. The pseudo-constructor of the xSubtitutingCls class can substitute the pseudo-constructor of the xMajorCls class using the setConstructor() method and constructor() method. As a result, the create() method of the xMajorCls class will create an instance of the xSubtitutingCls class. For example:

xSubstitutingCls::rxInit();                                          // Registering of the substituting class

OdRxClassPtr pSub = xSubstitutingCls::desc();                        // Getting of the describing instance 

odPrintConsoleString(L"\nThe substituting class describing instance = %x %s", pSub.get(), pSub->name().c_str());

// Prints: The substituting class describing instance = E5120B xSubstitutingCls

pCls->setConstructor(pSub->constructor());                           // Substituting of the pseudo-constructor

OdRxObjectPtr pInst7 = pCls->create();                               // Creating of a new instance

odPrintConsoleString(L"\nInstance 7 = %x , Class = %s [%x]", pInst7.get(), pInst7->isA()->name().c_str(), pInst7->isA());

// Prints: Instance 7 = 14B126 , Class = xSubstitutingCls [E5120B]

xSubstitutingCls::rxUninit();                                        // Unregistering of the substituting class

To recover the pseudo-constructor of the xMajorCls class, use the pseudoConstructor() static method which is the static default pseudo-constructor automatically generated by the RTTI macros. This method can be passed as an argument of the setConstructor() method. As a result, the create() and createObject() methods will again create an instance of its own class. For example:

pCls->setConstructor(xMajorCls::pseudoConstructor);

OdRxObjectPtr pInst8 = pCls->create();

odPrintConsoleString(L"\nInstance 8 = %x , Class = %s [%x]", pInst8.get(), pInst8->isA()->name().c_str(), pInst8->isA());

// Prints:  Instance 8 = 13A7B8 , Class = xMajorCls [14A208]

The substitution of pseudo-constructors provides the creation of instances of user-defined classes that have information of standard classes with expanded functionality at run-time.

The pseudo-constructor can also be defined as an ordinary function that does not have arguments and returns the smart pointer to the created instance. It provides the ability to use a specific user-defined class instead of the standard class being applied in such cases, initialize the properties subject to the current configuration, register the created instance in dictionaries, or apply another non-trivial process. For example, an instance of the xSubtitutingCls class must be created only once, that is, the application must not contain more than one instance of the xSubtitutingCls class. You can create a dictionary that will store the names of classes for which a single instance was created. The creating function will check whether the single instance of the specified class exists in the dictionary. If a single instance exists, the creating function will return the smart pointer to the existing instance. If a single instance does not exist, the creating function will create it and return the smart pointer to it. The user-defined creating function named MyCnstr has the following definition:

OdRxDictionaryPtr pSingleObjects;

OdRxObjectPtr MyCnstr()
{
  OdRxObjectPtr pNewObj;

  if(pSingleObjects->has(L"xSubstitutingCls"))
    pNewObj = pSingleObjects->getAt(L"xSubstitutingCls");
  else
  {
    pNewObj = xSubstitutingCls::createObject();
    pSingleObjects->putAt(L"xSubstitutingCls", pNewObj);
  }
  return pNewObj;
}

Use the following code for testing:

xSubstitutingCls::rxInit();                                          // Registering of the substituting class

pSingleObjects = odrxCreateRxDictionary();                           // Creating the dictionary

OdRxClassPtr pSub = xSubstitutingCls::desc();                        // Getting of the class describing instance

odPrintConsoleString(L"\nThe class describing instance = %x %s", pSub.get(), pSub->name().c_str());

// Prints: The class describing instance = E5120B xSubstitutingCls

pSub->setConstructor(MyCnstr);                                       // Set the user-defined pseudo-constructor

OdRxObjectPtr pInst9 = pSub->create();
odPrintConsoleString(L"\nInstance 9 = %x , Class = %s [%x]", pInst9.get(), pInst9->isA()->name().c_str(), pInst9->isA());

// Prints:  Instance 9 = 14C2A6 , Class = xSubstitutingCls [E5120B]

OdRxObjectPtr pInst10 = pSub->create();
odPrintConsoleString(L"\nInstance 10 = %x , Class = %s [%x]", pInst10.get(), pInst10->isA()->name().c_str(), pInst10->isA());

// Prints:  Instance 10 = 14C2A6 , Class = xSubstitutingCls [E5120B]

OdRxObjectPtr pInst11 = pSub->create();
odPrintConsoleString(L"\nInstance 11 = %x , Class = %s [%x]", pInst11.get(), pInst11->isA()->name().c_str(), pInst11->isA());

// Prints:  Instance 11 = 14C2A6 , Class = xSubstitutingCls [E5120B]

xSubstitutingCls::rxUninit();                                        // Unregistering of the substituting class

As a result, only the first call of the create() method creates a new instance, and all of the following calls do not create instances and returns the smart pointer to the existing instance. The user-defined pseudo-constructors can provide any complicated creation of instances together with processing at run-time.

See Also

RTTI Technology

Understanding Pseudo-Constructors

Implementing RTTI Methods for the Derived Class

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