Kernel SDK Developer's Guide > Run-Time Type Identification > Example of Identifying Classes
Example of Identifying Classes

Developers can use information about classes to check whether applying methods is correct for the specified instance and to select the type of data processing. To verify a class of an instance at run-time, use the isA() virtual method which returns the raw pointer to the class describing instance dynamically associated with the specified instance. With the class describing instance, you can use the name() method to get the class name and compare it with the required name. This allows you to identify the class of an instance and select the corresponding branch of your algorithm.

For example, consider three classes: a point, circle, and text. The point object is defined by two-dimensional coordinates of the position and color, the circle object is defined by two-dimensional coordinates of the center and radius, and the text object is defined by two-dimensional coordinates of the position and text content. The example implements the PrintAboutObject() function that must get the raw pointer to the specified instance of one of these classes and must print its specific data. The PrintAboutObject() function requiress one argument — the raw pointer of the OdRxObject class type — and it is unknown whether the specified instance has a type. To verify a type and correctly call the admissible methods, the example uses the isA() virtual method before converting a raw pointer to the required type and application of methods.

First, the example implements the xSomePoint class that provides the functionality of a point that must include creating a point, setting a position and color, and getting the X-coordinate, Y-coordinate, or color. Next, the example implements the xSomeCircle class that provides the functionality of a circle, which must include creating a circle, setting the position and radius, and getting the X-coordinate, Y-coordinate, or radius. Next, the example implements the xSomeText class that provides functionality of text that must include creating a text string, setting a text position and text content, and getting the X-coordinate, Y-coordinate, or text content. Next, the example implements the PrintAboutObject() function that prints the specific data of the specified instance. Last, the example implements the main() function that identifies instances by creating the array of instances from ten elements and fills it using instances of the xSomePoint, xSomeCircle, xSomeText classes. To select a class for creating an instance and specifying parameters of the instance, the main() function uses the generator of pseudorandom numbers. Therefore, instances for the PrintAboutObject() function will be created randomly both by type and parameter.

The example derives the xSomePoint, xSomeCircle, and xSomeText classes directly from the OdRxObject class. To declare the standard RTTI methods, the example uses the ODRX_DECLARE_MEMBERS macro. To implement the standard RTTI methods, the example uses the ODRX_CONS_DEFINE_MEMBERS macro.

Step 1. Implementing the xSomePoint class

The xSomePoint class defines point coordinates as double values and color as a 32-bit integer value. To manipulate points, this class declares the setPoint() method that specifies the position and color, the getX() method that returns the current X-coordinate, the getY() method that returns the current Y-coordinate, and the getColor() method that returns the current color. The xSomePoint class has the following definition:

class xSomePoint : public OdRxObjectImpl<OdRxObject>
{
 private:
   double x;
   double y;
   OdUInt32 color;
 public:
   ODRX_DECLARE_MEMBERS(xSomePoint);

   double getX() const;
   double getY() const;
   OdUInt32 getColor() const;
   void setPoint(double newX, double newY, OdUInt32 newColor);

   xSomePoint();
   ~xSomePoint();
};

typedef OdSmartPtr<xSomePoint> xSomePointPtr;

Its methods have the following implementation:

ODRX_CONS_DEFINE_MEMBERS(xSomePoint, OdRxObject, NEWOBJ_CONSTR);

xSomePoint::xSomePoint()  
{
  x = y = 0;  color = ODRGB(255, 255, 255);
}

xSomePoint::~xSomePoint() {}

double xSomePoint::getX() const  {  return x;  }

double xSomePoint::getY() const  {  return y;  }

OdUInt32 xSomePoint::getColor() const  {  return color;  }

void xSomePoint::setPoint(double newX, double newY, OdUInt32 newColor)
{
  x = newX;  y = newY;  color = newColor;
}

Step 2. Implementing the xSomeCircle class

The xSomeCircle class defines the center coordinates and radius of a circle as double values. To manipulate circles, this class declares the setCircle() method that specifies the center and radius, the getCenterX() method that returns the X-coordinate of a center, the getCenterY() method that returns the Y-coordinate of a center, and the getRadius() method that returns the radius. The xSomeCircle class has the following definition:

class xSomeCircle : public OdRxObjectImpl<OdRxObject>
{
 private:
   double center_x;
   double center_y;
   double radius;
 public:
   ODRX_DECLARE_MEMBERS(xSomeCircle);

   double getCenterX() const;
   double getCenterY() const;
   double getRadius() const;
   void setCircle(double newX, double newY, double newRadius);

   xSomeCircle();
   ~xSomeCircle();
};

typedef OdSmartPtr<xSomeCircle> xSomeCirclePtr;

Its methods have the following implementation:

ODRX_CONS_DEFINE_MEMBERS(xSomeCircle, OdRxObject, NEWOBJ_CONSTR);

xSomeCircle::xSomeCircle()  
{
  center_x = center_y = 0;   radius = 1;
}

xSomeCircle::~xSomeCircle() {}

double xSomeCircle::getCenterX() const  {  return center_x;  }

double xSomeCircle::getCenterY() const  {  return center_y;  }

double xSomeCircle::getRadius() const  {  return radius;  }

void xSomeCircle::setCircle(double newX, double newY, double newRadius)
{
  center_x = newX;
  center_y = newY;
  radius = ((newRadius < 0) ? -newRadius : newRadius);
}

Step 3. Implementing the xSomeText class

The xSomeText class defines the coordinates of a text position as double values and the text content as a OdChar string. To manipulate text, this class declares the setText() method that specifies the text position and text content, the getX() method that returns the X-coordinate of a text position, the getY() method that returns the Y-coordinate of a text position, and the getText() method that returns the text content. The xSomeText class has the following definition:

class xSomeText : public OdRxObjectImpl<OdRxObject>
{
 private:
   double pos_x;
   double pos_y;
   OdString text;
 public:
   ODRX_DECLARE_MEMBERS(xSomeText);

   double getX() const;
   double getY() const;
   const OdChar* getText() const;
   void setText(double newX, double newY, const OdChar* newText);

   xSomeText();
   ~xSomeText();
};

typedef OdSmartPtr<xSomeText> xSomeTextPtr;

Its methods have the following implementation:

ODRX_CONS_DEFINE_MEMBERS(xSomeText, OdRxObject, NEWOBJ_CONSTR);

xSomeText::xSomeText()  
{
  pos_x = pos_y = 0.0;
  text = OD_T(" ");
}

xSomeText::~xSomeText() {}

double xSomeText::getX() const  {  return pos_x;  }

double xSomeText::getY() const  {  return pos_y;  }

const OdChar* xSomeText::getText() const  {  return text.c_str();  }

void xSomeText::setText(double newX, double newY, const OdChar* newText)
{
  pos_x = newX;
  pos_y = newY;
  text = newText;
}

Step 4. Implementing the PrintAboutObject() function

The PrintAboutObject() function requires a raw pointer to the instance of information to be printed as an argument of the OdRxObject class type. The function uses the isA() method of the OdRxObject class to get the class describing instance and the name() method of the OdRxClass class to get the class name of the instance as a value of the OdString type. Then the function uses the compare() method of the OdString class to compare the class name with the required name for one of three classes: xSomePoint, xSomeCircle, or xSomeText. If the comparison is successful, the function converts the pointer to the corresponding type and calls the specific methods of the corresponding class. The PrintAboutObject() function has the following implementation:

void PrintAboutObject(const OdRxObject*  pObj)
{
  if(pObj->isA()->name().compare(L"xSomePoint") == 0) 
  {
    xSomePoint* pPoint = (xSomePoint*) pObj;
    odPrintConsoleString(L"\n[%x] Point (%g,%g) C(%x)", pPoint, pPoint->getX(), pPoint->getY(), pPoint->getColor());
  }
  else if(pObj->isA()->name().compare(L"xSomeCircle") == 0)
  {
    xSomeCircle* pCircle = (xSomeCircle*) pObj;
    odPrintConsoleString(L"\n[%x] Circle (%g,%g) R=%g", pCircle, pCircle->getCenterX(), pCircle->getCenterY(), pCircle->getRadius());
  }
  else if(pObj->isA()->name().compare(L"xSomeText") == 0)
  {
    xSomeText* pText = (xSomeText*) pObj;
    odPrintConsoleString(L"\n[%x] Text (%g,%g) \"%s\"", pText, pText->getX(), pText->getY(), pText->getText());
  }
}

Step 5. Implementing the testing functions

For testing RTTI methods for these classes, the main() function creates the array of non-typified smart pointers, creates ten instances of different types randomly and initializes their properties randomly. Then, the main() function initializes the generator of pseudorandom numbers using the srand() standard function and throws the current number using the rand() standard function. Using the random numbers, the main() function selects the class type of a new instance and initializes the properties of a new instance. To create a new instance, the function uses the pseudo-constructor of the corresponding class and saves the smart pointer returned by it in the array. To initialize the properties of a new instance, the function normalizes the current random number to the corresponding range using the RandRange macro and calls the corresponding set-method: setPoint(), setCircle(), or setText(). After creating and initializing, the main() function calls the PrintAboutObject() function for each instance to print its specific data. The Main module has the following implementation:

#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);
 public:
   MyApp() {};
};

#include <stdlib.h>
#include <conio.h>
#include <time.h>

#define FIELD_X_MAX 800
#define FIELD_Y_MAX 600
#define RandRange(Range) (((double)rand()/(double)RAND_MAX) * Range)

int main()
{
  OdStaticRxObject<MyApp> svcs;

  odInitialize(&svcs);
  xSomeCircle::rxInit();
  xSomePoint::rxInit();
  xSomeText::rxInit();

  OdRxObjectPtr Arr[10];

  srand( (unsigned)time( NULL ) );

  for(int i=0 ; i < 10 ; i++)
  {
    switch( (int)(RandRange(3)) + 1 )
    {
      case 1:
           Arr[i] = xSomePoint::createObject();
           ((xSomePointPtr) Arr[i])->setPoint( RandRange(FIELD_X_MAX), RandRange(FIELD_Y_MAX), 
                                               ODRGB(RandRange(255), RandRange(255), RandRange(255)) );
           break;

      case 2:
           Arr[i] = xSomeCircle::createObject();
           ((xSomeCirclePtr) Arr[i])->setCircle( RandRange(FIELD_X_MAX), RandRange(FIELD_Y_MAX), RandRange(100) );
           break;

      case 3:
           Arr[i] = xSomeText::createObject();
           ((xSomeTextPtr) Arr[i])->setText( RandRange(FIELD_X_MAX), RandRange(FIELD_Y_MAX), OD_T("Info") );
           break;
    }
  }

  for(int i=0 ; i < 10 ; i++)
    PrintAboutObject(Arr[i].get());
  getch();
  
  xSomeText::rxUninit();
  xSomePoint::rxUninit();
  xSomeCircle::rxUninit();
  odUninitialize();

  return 0;
}

The first generating and printing of instances gives the following result:

[a418] Circle (44.7523,461.293) R=67.6473
[a440] Text (230.305,584.747) "Info"
[a478] Text (110.16,10.9134) "Info"
[a4a0] Point (711.594,419.892) C(61f011)
[a4c8] Text (694.015,551.384) "Info"
[a4f0] Circle (474.966,136.857) R=80.0317
[a518] Circle (682.467,284.39) R=96.1425
[a540] Point (551.286,43.8002) C(77fdb0)
[a568] Point (374.548,8.16675) C(a30473)
[a590] Text (226.399,88.6807) "Info"

The second generating and printing of instances gives the following result:

[b418] Point (573.553,276.901) C(4d4254)
[b440] Circle (570.257,382.153) R=55.1714
[b468] Circle (543.913,122.611) R=52.3453
[b490] Point (576.458,237.953) C(7d3955)
[b4b8] Circle (646.236,192.486) R=43.2417
[b4e0] Circle (29.664,7.23289) R=41.0535
[b508] Text (711.765,424.287) "Info"
[b540] Text (379.138,184.759) "Info"
[b568] Circle (639.302,72.7134) R=46.1257
[b590] Point (292.611,257.271) C(8da9e2)

See Also

RTTI Technology

Functionality of RTTI

Implementing RTTI Methods for the Derived Class

Registering and Unregistering Classes in a Program

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