Purpose. The "case" statement considered harmful Discussion. The pgming style that uses a struct with a "type" field to denote its contents causes "case" stmts to be scattered throughout the program. The problem with this style is that the code to deal with each "type" is everywhere the struct is referenced. To change a "type", or add a new one, a pgmer must find and modify all the case stmts, which is tedious and error-prone. In C++, you can always replace this use of case stmts by derived classes with virtual functions. A derived class represents each struct "type", and a virtual function call replaces each case stmt. enum ObjType { CIRC, RECT, LINE }; Each conditional branch in a case stmt becomes a virtual member function of struct Circ { one of the derived classes, and dynamic int radius; binding eliminates the need for keeping }; a "type" field in the struct. This localizes and encapsulates all the code struct Rect { that deals with "type" processing. int width; Adding a new "type" is simply a matter int height; of creating an additional derived class }; without modifying any existing code. [Gorlen, Orlow, Plexico, NIH class lib] struct DisplayObj { ObjType type; struct DisplayObj union { { Circ circ; virtual void display() = 0; Rect rect; }; }; }; struct Circ : DisplayObj { void displayCirc( Circ* c ) { int radius; cout << "radius is " << c->radius << endl; Circ( int r ) { } radius = r; void displayRect( Rect* r ) { } cout << "width is " << r->width void display() { << ", height is " << r->height cout << "radius is " << radius << endl; << endl; } } }; void main( void ) { struct Rect : public DisplayObj Circ aCirc = { 5 }; { Rect aRect = { 3, 4 }; int width; const int NUM = 2; int height; DisplayObj list[NUM]; list[0].type = CIRC; Rect( int w, int h ) { list[0].circ = aCirc; width = w; list[1].type = RECT; height = h; list[1].rect = aRect; } void display() { for (int i=0; i < NUM; i++) cout << "width is " << width switch( list[i].type ) << ", height is " << height { << endl; case CIRC: } displayCirc(&list[i].circ); }; break; case RECT: void main( void ) displayRect(&list[i].rect); { break; Circ aCirc( 5 ); default: Rect aRect( 3, 4 ); cout << "Unknown type: " const int NUM = 2; << list[i].type << endl; DisplayObj* list[NUM] = } { &aCirc, &aRect }; } for (int i=0; i < NUM; i++) // radius is 5 list[i]->display(); // width is 3, height is 4 } Purpose. "Don't ask, don't tell" Discussion. "The root problem with both 'type' queries and 'capability' queries in OO design is that some of the essential behavior of an object is determined externally to the object itself. This approach runs counter to the principle of data abstraction, perhaps the most basic of the foundations of object-oriented programming. With these approaches, the meaning of an abstract data type is no longer encapsulated within the class used to implement it, but is distributed throughout the source code." [Stephen Dewhurst, C++ Report, May 2000, p35]