Object-Oriented Programming Using SOM and DSOM:A Complement to C++:Run-Time Type Identification

From EDM2
Jump to: navigation, search

Currently, C++ provides no support for determining the type of an object at runtime. The need for run-time type identification arises in an inheritance hierarchy, when methods can be supported in one derived class, but not in the others. Given a pointer to the base class, it becomes necessary to check the type of the object to make sure that one can safely invoke a particular method.

While run-time type identification can be avoided to a large extent by using virtual functions, there are cases where it is not possible. For example, a user might want to extend the function of a class by subclassing, but cannot add or modify the original class to use virtual functions, because the source code of the original class is not available. This represents a legitimate case of using runtime type identification. Indeed, one of the language extensions that has been accepted by the C++ committee is the run-time type identification proposal by Stroustrup and Lenkov.

SOM provides methods that let you query information about an object at runtime. In particular, the somlsA method lets you determine whether an object is an instance of a given class. You invoke somlsA on a target object, passing the class object that the target object should be tested against, as an input parameter. It returns true, if the object is an instance of the specified class, otherwise it returns false.

How do you get a pointer to a class object that you want to test against? We have already discussed a number of ways. One way is to invoke the <className> NewClass procedure, which creates and returns a pointer to the class object of the specified class. Another way is to use the som.FindClslnFile or the som.FindClass method, if the language bindings for the class are not available at compile time. A third way is to use the ClassData structure that we discussed in Section 4.1.2 on page 75.

Recall that each class has a global data structure, named <className>ClassData. This data structure contains a pointer to the class object, which is built during initialization. Therefore, if you have the usage bindings file for the class, you can obtain a pointer to the class object by specifiying <className>ClassData. classObject.

The following example illustrates the above points. Consider the following interfaces:

interface Employee : SOMObject
     short salary();
interface Manager : Employee
     short bonus ();     // Manager receives bonus on top of  base salary
interface Programmer : Employee
    short overtime ();  // Programmer receives overtime paid

A client program, which calculates the salary for an employee, might be written as follows:

calcSalary(Employee ·emp)
  SOMClass *mgrCiass;
  Environment •ev = somGetGiobaiEnvironment(};
  // Use the ClassData structure to get the pointer to the Programmer class object
  if (emp->somlsA(ProgrammerCiassData.classObject))
      cout << "Programmer salary: " ;
      cout « (emp->salary(ev) + ((Programmer*)emp)->overtime(ev));

 // Create a Manager class object using ManagerNewClass
 / *****************************************************
  mgrClass = ManagerNewCiass(O,O);
  if ( emp->somlsA(mgrCiass) )
      cout <<"Manager salary: " ;
      cout « (emp->salary(ev) +((Manager·) emp)->bonus(ev));

When calcSalary is called with a pointer that points to a Programmer object, the first somisA test will be successful and the overtime method is called on the Programmer object. When calcSalary is called with a pointer that points to a Manager object, the second somlsA will be successful and the bonus method is called.

The preceding example also illustrates two different ways of getting a pointer to a class object. In the :first case, the expression ProgrammerClassData.classObject is used. In the second case, the procedure ManagerNewClass is used.