Path: utzoo!attcan!utgpu!jarvis.csri.toronto.edu!cs.utexas.edu!sun-barr!rutgers!att!cbnewsl!dog From: dog@cbnewsl.ATT.COM (edward.n.schiebel) Newsgroups: comp.lang.c++ Subject: Re: Design Problem Message-ID: <3164@cbnewsl.ATT.COM> Date: 5 Dec 89 15:11:03 GMT References: <22137@brunix.UUCP> Organization: AT&T Bell Laboratories Lines: 78 From article <22137@brunix.UUCP>, by sdm@cs.brown.edu (Scott Meyers): > ... description of design problem. A list of base class objects, but > Scott wants to iterate over it and call functions which are only defined > on some of the derived classes... > > It seems I have three possible approaches: > > 1. Define evaluate() as a virtual function in ARC, and redefine it > appropriately in EXECUTABLE_ARC. In ARC, make it a noop, so when > called on NONEXECUTABLE_ARCs, it won't do anything. IMHO, this is the purest solution. If there are operations you want to perform on a collection of objects, then all those objects better define that operation. From a philisophical point of view, is see nothing wrong with considering NONEXECUTABLE_ARCS as ARCs whose evaluate() is a noop. > > 2. Add an enumerated type to ARC that enumerates each of the subtypes, > and add a virtual function arc_type() that is redefined in each > subclass to return the appropriate value. Then I can write code > like "if (arc->arc_type() == EXECUTABLE) arc->evaluate()". I found a need to do this once (or twice :-), but (as you mention later) it suffers from having to modify the base class when you derive a new type from it. I have a variation on this theme which does not suffer from this weakness: class base { public: virtual String type(); }; class derived : public base { pubic: static String Stype() {return type_string;} String type() {return Stype();} private: static String type_string; // initialized to "derived" in .c file }; Not the test becomes: if(base_ptr->type() == derived::Stype()) doSomething() (assuming class String has operator== defined of course). This test (a String comparison) is not that much more expensive than an integer test, since in many cases, the comparison will fail in the first character (unless your clas hierarchy looks like arc_generic, arc_this, arc_that, arc_theotherthing). > > 3. Separate my ARC class into two distinct classes, so I never have > this problem. If there are specific places in the code where you want to deal with one type of ARC only, and use it as a SPECIAL_ARC, not the generic variety, then maybe you need to keep a collectio of SPECIAL_ARCs around for this purpose. > None of these designs is attractive. The first one doesn't extend well to > situations in which there may be many functions like evaluate() down in the > hierarchy -- each will have to be defined in ARC, even though they have > nothing to do with generic ARCness. Then, maybe you shouldn't be trying to use the special functions in elements of a GENERIC_ARC collection. > In addition, it suffers from the same > problem that the second one does: adding new classes to the hierarchy may > require that I modify the base class (e.g., adding new enumerated type > values). See my solutino above. > The third option is impractical because, although the class ARC > breaks down well along executability, there are many other aspects of ARCs > that don't separate so easily -- I really do want to have a single ARC > superclass. But maybe also keep the special cases collected together too. Hope this is of some help. Ed Schiebel AT&T Bell Laboratories dog@vilya.att.com