TITLE: Checking types at run-time. PROBLEM: Ajay Kamdar (adk@enigma.Warren.MENTORG.COM) Assume that I am using the power of virtual functions. Assume that I am not using enum and a switch statement to simulate a virtual function. Assume that the code specific to an object is part of that object. Assume that the function foo() is defined for all the shapes. Instead of calling it foo(), call it display(). After these assumptions, what we now have is: A list of shapes. Shapes are either circles, triangles, or squares. Each shape has a virtual display() function which knows how to display the shape. The problem: given the list described above, display all the circles only. So how would you do it without having a virtual isA() query function for the shapes? RESPONSE: Bob (???) Consider the following approach. #include class Shape { public: virtual ~Shape() {}; virtual void display( void * ) {cout << "Shape display( void * )\n";}; virtual void display() { cout << "Shape display()\n" ; } ; }; class Circle : public Shape { static int CIRCLE ; public: static void *aCircle() {return &CIRCLE;} virtual void display( void * displayType ){ if (displayType == &CIRCLE) display() ; } void display() { cout << "Circle\n" ; } ; ~Circle() {} ; }; class Triangle : public Shape { static int TRIANGLE ; public: void *aTriangle() {return &TRIANGLE;} void display( void * displayType ) { if (displayType == &TRIANGLE) display() ; } void display() { cout << "Triangle\n" ; } ; ~Triangle() {} ; }; int main() { Shape *list[100] ; int i = 0 ; // add arbitrary shapes (circles, triangles, squares) to the list list[i++] = new Circle ; list[i++] = new Triangle ; list[i++] = new Circle ; list[i++] = new Circle ; list[i++] = new Triangle ; list[i++] = new Circle ; list[i++] = new Circle ; list[i++] = new Circle ; list[i++] = new Triangle ; list[i++] = new Circle ; list[i++] = new Circle ; list[i++] = new Triangle ; list[i++] = NULL ; // Now say you want to process only the circles in the list for ( i = 0 ; list[i] ; i++ ) list[i]->display( Circle::aCircle() ) ; cout << "end Circle list.\n\n" ; // Now say you want to process all members of the list for ( i = 0 ; list[i] ; i++ ) list[i]->display() ; cout << "end complete list.\n\n" ; } Each class distinguishes its type based on the address of a static member. In each class a static member function exports a type descriptor as an opaque entitiy, i.e., a void * pointer. For each virtual member function that we wish to constrain we define another member function that accepts a type descriptor and, internally, decides if the actual member function should be called. This solution accomplishes the same functionality as the enum-based example, but isolates knowledge of types in the derived classes. This reduces the effort required to add a new derived type, e.g., Square, since we no longer change Shape. If we didn't want an additional member function, we could redefine display() with a default parameter, e.g., virtual void display( void * displayType = NULL ); then code the display function to consider NULL as equilavent to the instance type. Doing this involves an additional NULL check, which may or may not be acceptable in a particular situation.