Path: utzoo!attcan!uunet!lll-winken!lll-tis!helios.ee.lbl.gov!pasteur!ames!elroy!jpl-devvax!beowulf!david From: david@beowulf.JPL.NASA.GOV (David Smyth) Newsgroups: comp.lang.c++ Subject: Re: Problem with multiple inheritance? Message-ID: <3451@jpl-devvax.JPL.NASA.GOV> Date: 2 Nov 88 21:05:13 GMT References: <8335@nlm-mcs.arpa> <3438@jpl-devvax.JPL.NASA.GOV> <1140@microsoft.UUCP> Sender: news@jpl-devvax.JPL.NASA.GOV Reply-To: david@beowulf.JPL.NASA.GOV (David Smyth) Organization: Jet Propulsion Laboratory, Pasadena, CA. Lines: 97 tonyw@microsoft.UUCP (Tony Williams) writes: >david@beowulf.JPL.NASA.GOV (David Smyth) writes: >>only use multiple-inheritance when you have the source of all classes >>back to their roots because a client can introduce bugs which a C++ >>compliler won't catch; ... > >Is this described anywhere in the literature? Can anyone tell me about >the problems referred to here? The problem was discussed in several sessions at the USENIX C++ conference in Denver two weeks ago, including the tutorials given by Jonathan Shopiro. The concept is: any time a class exists more than once in a multiple inheritance heirarchy, then that class should be declared as "virtual." Shopiro gave the following example: class List { ... }; // Something which can be on a list. class Window { ... }; // A window. class Bordered : public List, virtual public Window { ... }; // A bordered window on a list. class Labeled : public List, virtual public Window { ... }; // A labeled window on a list. class Fancy : public Bordered, public Labeled { ... }; // A bordered, labeled window on TWO lists - // clear as mud, right? And here is more illumination: if the object library author did not specify that Window was a virtual base class of Bordered and Labeled, but just a base class, then Fancy would consist of TWO windows! You would not have one with characteristics (member data and member functions) of both, rather you would have a new class with a Bordered window, and a Labeled window. Isn't that just so obvious? Won't all of your average programmers simply have a wonderful time with this new feature? :-( Note that the object library author must consider which class may be combined with which other classes, and then declare any intersections of their inheritance heirarchies to be virtual - well, if you want that part of their characteristics to combine, any way. Simple, isn't it? :-( Note that the derived classes change radically when a base class is altered - Fancy will be on a single list, not two, if the definition of EITHER Bordered or Labeled is changed to make List a virtual base class. That is theoretically OK, since any change to a base class may impact any derived classes. Practically, however, it is a can of worms. Other problems: when Fancy overrides a Window method, its OK, because Fancy has only one Window. If it overrides a List method, nope: ambiguous. True, the compiler says so. But the author of Fancy must know the inheritance of the classes in the library to make sure the appropriate method is overriden. Notice that simply a complete list of names visible in the Bordered and Labeled classes is not enough: the client (Fancy) author must also know the internal structure of the library. Not very re-usable. And more: you lose substitutablity when you use a virtual base class. Fancy cannot be on a list of windows, because you can't cast a pointer declared as a pointer to Window into a pointer to Fancy, or Bordered or Labeled for that matter. Again, not very useful. Imagine this bug: the window system object library has a Refresh method, which causes all windows to repaint. A client creates a new class with Window a virtual base class, and overrides the refresh method (of course). Hmm. That window won't refresh. How nicely obscure. :-( What to use instead: Member objects! class List { ... }; // exactly as above. class Window { ... }; // ditto. class Border { ... }; // Border attrs and methods. class Label { ... }; // Label attrs and methods. class Bordered : Window // Inherit most significant characteristics { List borderedList; Border myBorder; ... }; // Window with border, on a list. class Labeled : Window { List labeledList; Label myLabel; ... }; // Window with label, on a list. class Fancy : Window { List labeledList, borderedList; Border myBorder; Label myLabel; ... }; // Labeled, bordered window on two lists. True, more classes, and that is always a pain. TANSTAAFL - There aint no such thing as a free lunch. There is such a thing as obscurity however. Neither member objects nor multiple inheritance provide a free lunch, but only one is obscure... Let your Joe Average programmers prove it to you!