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:
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:
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.
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.
|