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

A pseudo-constructor is a function that creates an instance of the class for which it is defined. This function does not have arguments and returns the smart pointer to a new instance of the defined class. Pseudo-constructors hide the mechanism for creating instances and allow a program to create instances from classes that are not derived from those classes whose instances they create. The creating of an instance can include the initializing of its properties subject to the current configuration, registering of the created instance in dictionaries or tables, attaching data to the created instance, or other actions that require the existing instance of the defined class and must be performed together with its creation.

The base functionality of pseudo-constructors is focused in class describing instances that are created for each registered class. Each class describing instance stores its own pseudo-constructor. The OdRxClassConsImpl class declares the m_pConstr member of the OdPseudoConstructorType type when it implements the class describing object. OdPseudoConstructorType is the pointer to the function that creates an instance of the class. This function has no have arguments and returns the non-typified smart pointer to a new instance. The pseudo-constructor type has the following definition:

typedef OdRxObjectPtr (*OdPseudoConstructorType)();

The newOdRxClass() global function initializes the m_pConstr member using an argument when it creates the class describing instance. The function creates an instance of the OdDxfClassImpl class and uses its init() method to initialize it using information about the created class. The OdDxfClassImpl class is the successor of the OdRxClass class and implements the class describing instance. The ODRX_**_DEFINE_MEMBERS_** macros implementing RTTI methods for Rx classes generate the cpp-code for pseudo-constructors using the EMPTY_CONSTR, NEWOBJ_CONSTR, RXIMPL_CONSTR substitution macros that 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()

These macros are passed as parameters of the RTTI macros. However, developers can define their own substituting macros and pass them to the RTTI macros when creating instances is complicated for the derived class. The RTTI macros pass the cpp-code of a pseudo-constructor generated by the substitution macro in the class describing instance when they create the implementation of the RTTI methods. Specifically, they initialize the m_pConstr member using a pointer to the generated function of the pseudo-constructor. The RTTI methods use the m_pConstr member for creating instances.

The m_pConstr member provides the ability to dynamically define pseudo-constructors for registered classes. The pointer to the creating function can be changed to another pointer at run-time. This allows substituting pseudo-constructors at run-time, for example, when the application requires a specific user-defined class instead of the standard class applied in such cases, but when the specific user-defined class must have the same registration information as the standard class. The substitution of the creating function (that is, pseudo-constructor) in the class describing instance can provide the ability to create instances of a user-defined class with information of the standard class.

The rxInit() static method of an Rx class calls the newOdRxClass() global function and passes it the pointer to the creating function generated by the RTTI macros. Only registered classes can use the pseudo-constructors for creating instances. To use the pseudo-constructors, the derived class must declare the RTTI methods using the ODRX_DECLARE_MEMBERS macro in its own public section and must define their implementation using one of the ODRX_**_DEFINE_MEMBERS_** macros in the cpp-code. If the class is not registered, calling its pseudo-constructors will generate the eNotApplicable exception.

To create an instance of the registered class from the class describing instance, use the create() method of the OdRxClass class, which does not require arguments and returns the non-typified smart pointer to a new instance of the registered class. This method creates a new instance using the pseudo-constructor specified by the m_pConstr member of the class describing instance and returns the smart pointer returned by the creating function of the pseudo-constructor. This method generates the eNotApplicable exception when the pseudo-constructor is not specified. The create() method has the following implementation:

OdRxObjectPtr OdRxClassConsImpl::create() const
{
  if(!m_pConstr)
    throw OdError(eNotApplicable);
  return m_pConstr();
}

The ODRX_DECLARE_MEMBERS macro declares the pseudoConstructor() static method which is the default pseudo-constructor of the class derived from the OdRxObject class. The RTTI macros automatically generate the cpp-code for the pseudoConstructor() static method and pass the pointer to this function in the newOdRxClass() global function when registering the class. The default pseudo-constructor can not be changed because it is the static method created by macros for each class by default. The ODRX_DEFINE_PSEUDOCONSTRUCTOR macro generates the following code for it:

#define ODRX_DEFINE_PSEUDOCONSTRUCTOR(ClassName,DOCREATE)  \
OdRxObjectPtr ClassName::pseudoConstructor() {  return OdRxObjectPtr(DOCREATE(ClassName));  }

Where DOCREATE is one of substitution macros: EMPTY_CONSTR, NEWOBJ_CONSTR, RXIMPL_CONSTR, or user-defined. The default pseudo-constructor is applied for setting the pseudo-constructor in the class describing instance when it is created or recovered after substituting from the specific user-defined class. You should not use the pseudoConstructor() method directly.

To get the pseudo-constructor from the class describing instance, use the constructor() method of the OdRxClass class which does not require arguments and returns the value of the m_pConstr member as the OdPseudoConstructorType type which is as a pointer to the creating function. The constructor() method has the following implementation:

OdPseudoConstructorType OdRxClassConsImpl::constructor() {  return m_pConstr;  }

To set the pseudo-constructor in the class describing instance, use the setConstructor() method of the OdRxClass class which requires the pointer to the creating function as an argument of the OdPseudoConstructorType type and does not return a value. This method sets the m_pConstr member and has the following implementation:

void OdRxClassConsImpl::setConstructor(OdPseudoConstructorType pConstr)
{
  if(pConstr)
    m_pConstr = pConstr;
  else
    m_pConstr = emptyConstructor;
}

static OdRxObjectPtr emptyConstructor() {  return (OdRxObject*)0;  }

To create an instance of the registered class, use the createObject() static method of the derived class which does not require arguments and returns the typified smart pointer to a new instance. The ODRX_DECLARE_MEMBERS macro automatically generates the code for the createObject() static method of the specified class as the function that calls the create() method of the associated class describing instance. Therefore the class must be registered. The createObject() method has the following implementation:

#define ODRX_DECLARE_MEMBERS(ClassName)              \
public:                                              \
 static OdSmartPtr<ClassName> createObject()         \
 {                                                   \
   if(!desc()) throw OdError(eNotInitializedYet);    \  
     return desc()->create();                        \ 
 }                                                   \

The createObject() method refers to the class describing instance using the static association provided by the desc() method and calls the create() method of the class describing instance. If the class is not registered, this method generates the eNotInitializedYet exception.

The OdRxObjectImpl template class also automatically generates the cpp-code for the createObject() static method when it creates the implementation of the reference counting functionality for the class wrapped by it. The createObject() method has the following implementation:

static OdSmartPtr<TInterface> createObject()
{
  return OdSmartPtr<TInterface>(static_cast<TInterface*>(new OdRxObjectImpl<T, TInterface>), kOdRxObjAttach);
}

To create an instance of the registered class, you can also use the odrxCreateObject() global function which requires the class name as an argument of the OdString type, checks whether the class name exists in the class dictionary, creates a new instance of the class if and only if its class describing instance exists in the dictionary using the create() method, and returns the non-typified smart pointer to the created instance or NULL if the class is not registered. The odrxCreateObject() global function has the following implementation:

OdRxObjectPtr odrxCreateObject(const OdString& szClassName)
{
  OdRxClass* pClass = (OdRxClass*)odrxClassDictionary()->getAt(szClassName).get();
  if(pClass)
  {
    return pClass->create();
  }  
  return (OdRxObject*)0;
}

Note: Pseudo-constructors have a wide application for creating dynamic instances. Static instances do not require pseudo-constructors.

See Also

RTTI Technology

Functionality of Pseudo-Constructors

Implementing RTTI Methods for the Derived Class

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