TITLE: Should classes identify themselves? [JA] = aldrin@sctc.com (John Aldrin) [RM] = rmartin@rcmcon.com (Robert Martin), 16 Dec 93 [JA] Should classes be able to uniquely identify themselves? Shape - circle - ellipse - line ... etc In any case there seems that some code would exist that would have to know exactly what kinds of shapes exist and, this code would have to be modified each time a new shape is added. No big deal though. [RM] Stop. This IS a big deal. There is little point to using OO if you can't control which code is closed against the addition of new types. Being able to close modules against such additions is one of the major benefits of OO. e.g. void DisplayList(Set s) { for(Iterator i(s); i; i++) (*i)->Draw(); } The above code is closed to the addition of new varieties of shapes. New shapes can be added, and the above code does not need to be changed. The more code like this that you have, the more stable and robust your application will be. On the other hand: void CountShapes(Set s) { for(Iterator i(s); i; i++) { if (typeid(**i) == typeid(circle)) circle_cnt++; else if (typeid(**i) == typeid(square)) square_cnt++; else if ... } } The above code is not closed to the addition of new types of shapes. Moreover, when a new kind of shape is added, the above code will compile and run nicely! ACK! If such code exists in your application, you must hunt it all down, modify it all appropriately and then pray that you found every case and that you implemented every case appropriately. [...] [JA] Also, if there is a need for classes to id themselves is there some standard/style/precedent? [RM] There is a way. Of course it cannot be closed against the addition of new types, but it does provide compile time checking that you have found all the cases that need changing. class ShapeHandler; class Shape { public: virtual void Handle(ShapeHandler&) = 0; }; class Circle : public Shape { public: virtual void Handle(ShapeHandler& h) {h.HandleCircle(*this);} }; class Square : public Shape { public: virtual void Handle(ShapeHandler& h) {h.HandleSquare(*this);} }; class ShapeHandler { public: virtual void HandleCircle(Circle&) = 0; virtual void HandleSquare(Square&) = 0; }; Using these classes we can write the code which counts types in a list.. class ShapeCounter : public ShapeHandler { public: ShapeCounter() : itsSquares(0), itsCircles(0) {} void HandleCircle(Circle&) {itsCircles++} void HandleSquare(Square&) {itsSquares++} private: int itsSquares; int itsCircles; }; void CountShapes(Set s) { ShapeCounter c; for (Iterator i(s); i; i++) (*i)->Handle(c); } Clearly, none of the derivatives of ShapeHandler (e.g. ShapeCounter) can be closed against the addition of new types. However when new types are created, the base class ShapeHandler will be changed as well, and then all derivatives will refuse to compile until the new pure virtual function has been overridden. Moreover, the CountShapes function *is* closed. This allows you to separate the functions which are closed against new types, from the functions which are not. You can easily enumerate the classes which will need to change when new kinds of shapes are added. It is the ability to exert this kind of control over dependencies that makes OO a valuable tool. If this control is not exerted, then OO degrades to a set of "neat tricks" with little or no important value.