sdm@cs.brown.edu (Scott Meyers) (01/26/91)
Look, I've used single inheritance, both public and private, and multiple inheritance, with virtual base classes no less, but I've never yet come up with a plausible reason for wanting nonvirtual base classes in an application using MI in an inheritance DAG. If you have an application that uses nonvirtual base classes in an inheritance DAG, I'd appreciate it if you'd drop me a line briefly describing what you do and why you need duplicated base classes. Thanks, Scott ------------------------------------------------------------------------------- What do you say to a convicted felon in Providence? "Hello, Mr. Mayor."
Reid Ellis <rae@gpu.utcs.toronto.edu> (01/30/91)
In <62555@brunix.UUCP> sdm@cs.brown.edu (Scott Meyers) writes: >Look, if you have an application that uses nonvirtual base classes in >an inheritance DAG, I'd appreciate it if you'd drop me a line briefly >describing why you need duplicated base classes. Because the compiler is broken and doesn't handle virtual base classes properly? :-) Reid -- Reid Ellis 176 Brookbanks Drive, Toronto ON, M3A 2T5 Canada rae@gpu.utcs.toronto.edu || rae%alias@csri.toronto.edu CDA0610@applelink.apple.com || +1 416 446 1644
mjv@objects.mv.com (Michael J. Vilot) (01/31/91)
Scott Meyers asked for an example of using multiple inheritance without using virtual base classes. I used exactly this approach in the design of the C++ Booch Components library, to use mixin classes to achieve a couple of purposes. First, let me point out that the Booch Components library has a ``forest'' architecture, and thus avoids the common base class arrangement that leads to the complexities of using MI in that context. Second, I used private and public base classes for different design purposes. The first use I made of MI was to create ``concrete'' classes from abstract base classes (ABCs). These concrete classes had both the ABC and a base class for representation. With this arrangement, the library can provide alternate implementations of the ABC, each with different time/space complexity. In this case, the base class for representation is a second, private base class. The second use I made of MI was to mix in specific behavior for Node classes in the unbounded representations. Some of the Booch Components are what we call ``polylithic'' structures. That is, they can share their representation among several objects. Shared_Nodes are kinds of Nodes that mix in a Shared base class. This approach let me build the Shared class once (implementing reference counting), and mix it in as needed. The library also supports Managed components, which take over free list management from the global operators new and delete. A Managed_Node mixes in a base class Managed, which provides the class-specific operators new and delete. Again, I only had to build that mechanism once to use it in various places. I found the result to be quite satisfactory. It clearly represents the design structure, and helps keep the large library fairly well organized. I think the key to this is the separation between ``type'' and class that Doug Lea and Marshall Cline described in their paper ``An Object Oriented Graphical Design Method that Distinguishes Types from Classes'' that they presented at the GOOSE workshop at ECOOPSLA last October. -- Mike Vilot, ObjectWare Inc, Nashua NH mjv@objects.mv.com (UUCP: ...!decvax!zinn!objects!mjv)
linton@sgi.com (Mark Linton) (02/01/91)
In article <1159@zinn.MV.COM>, mjv@objects.mv.com (Michael J. Vilot) writes: |> Scott Meyers asked for an example of using multiple inheritance without using |> virtual base classes. I used exactly this approach in the design of the C++ |> Booch Components library, to use mixin classes to achieve a couple of purposes. I think you missed the point of Scott's question. You describe a situation in which you did not need virtual base classes. What Scott asked is if any one needs non-virtual base classes. Presumably, your code would have functioned correctly if you had made all your derivations virtual (in fact, you really should make all your reference counting derivations virtual because you don't want a descendant to have multiple ref counts). I would like to echo the original question, as I also have not encountered a situation where I need non-virtual base classes.
sdm@cs.brown.edu (Scott Meyers) (02/01/91)
In reponse to my posting, Michael J. Vilot described his uses of nonvirtual
base classe with MI. His examples were interesting, but I didn't see any
uses of a DAG. Perhaps I wasn't explicit enough in what I was looking for.
What I want to see is an example that can be boiled down to this:
A class A { ... };
/ \
/ \
B C class B: public (or private) A { ... };
\ / class C: public (or private) A { ... };
\ /
D class D: (optionally virtual) public (or private) B,
(optionally virtual) public (or private) C { ... };
What's important here is that neither B nor C inherits from A as a virtual
base. That results in the memory layout of a D object looking like this,
at least conceptually:
+------------+
| B's A Part |
+------------+
| B Part |
+------------+
| C's A Part |
+------------+
| C Part |
+------------+
| D Part |
+------------+
Notice that there are two A parts in a D object.
For the record, I fully agree with Michael's distinction between public and
private inheritance. I'm especially interested in examples of the above
the use only public inheritance.
Scott
-------------------------------------------------------------------------------
What do you say to a convicted felon in Providence? "Hello, Mr. Mayor."kgorlen@helix.nih.gov (Keith Gorlen) (02/02/91)
In article <1159@zinn.MV.COM>, mjv@objects.mv.com (Michael J. Vilot) writes: |> Scott Meyers asked for an example of using multiple inheritance without using |> virtual base classes. I used exactly this approach in the design of the C++ |> Booch Components library, to use mixin classes to achieve a couple of purposes. |> |> First, let me point out that the Booch Components library has a ``forest'' |> architecture, and thus avoids the common base class arrangement that leads to |> the complexities of using MI in that context. Second, I used private and |> public base classes for different design purposes. |> |> The first use I made of MI was to create ``concrete'' classes from abstract |> base classes (ABCs). These concrete classes had both the ABC and a base class |> for representation. With this arrangement, the library can provide alternate |> implementations of the ABC, each with different time/space complexity. In this |> case, the base class for representation is a second, private base class. It seems to me that there is little, if any, advantage to using private inheritance as opposed to simply including an instance of the class as a member variable, e.g.: class Concrete: public ABC, private Rep { // ... public: void foo(); }; void Concrete::foo() { Rep::f(); // ... } versus: class Concrete: public ABC { Rep rep; // ... public: void foo(); }; void Concrete::foo() { rep.f(); // ... } Are there more compelling reasons for using private inheritance than this? |> The second use I made of MI was to mix in specific behavior for Node classes in |> the unbounded representations. Some of the Booch Components are what we call |> ``polylithic'' structures. That is, they can share their representation among |> several objects. Shared_Nodes are kinds of Nodes that mix in a Shared base |> class. This approach let me build the Shared class once (implementing reference |> counting), and mix it in as needed. The library also supports Managed |> components, which take over free list management from the global operators new |> and delete. A Managed_Node mixes in a base class Managed, which provides the |> class-specific operators new and delete. Again, I only had to build that |> mechanism once to use it in various places. |> Is this also a case of private inheritance? |> -- |> Mike Vilot, ObjectWare Inc, Nashua NH |> mjv@objects.mv.com (UUCP: ...!decvax!zinn!objects!mjv) -- Keith Gorlen phone: (301) 496-1111 Building 12A, Room 2033 FAX: (301) 402-0007 National Institutes of Health uucp: uunet!kgorlen%alw.nih.gov Bethesda, MD 20892 Internet: kgorlen@alw.nih.gov
kgorlen@helix.nih.gov (Keith Gorlen) (02/02/91)
In article <63176@brunix.UUCP>, sdm@cs.brown.edu (Scott Meyers) writes: |> In reponse to my posting, Michael J. Vilot described his uses of nonvirtual |> base classe with MI. His examples were interesting, but I didn't see any |> uses of a DAG. Perhaps I wasn't explicit enough in what I was looking for. |> What I want to see is an example that can be boiled down to this: |> |> A class A { ... }; |> / \ |> / \ |> B C class B: public (or private) A { ... }; |> \ / class C: public (or private) A { ... }; |> \ / |> D class D: (optionally virtual) public (or private) B, |> (optionally virtual) public (or private) C { ... }; |> |> What's important here is that neither B nor C inherits from A as a virtual |> base. That results in the memory layout of a D object looking like this, |> at least conceptually: |> |> +------------+ |> | B's A Part | |> +------------+ |> | B Part | |> +------------+ |> | C's A Part | |> +------------+ |> | C Part | |> +------------+ |> | D Part | |> +------------+ |> |> Notice that there are two A parts in a D object. |> Then I would draw the DAG like this: A A | | B C \ / D Examples 13-1 and 13-2 in "Data Abstraction and Object-Oriented Programming in C++" show multiply inheriting from class Link so that derived classes can be threaded on multiple linked lists; i.e. class A = Link, class B = AllLink, class C = QLink, and class D = Vehicle. However, Tom Cargill's article in the most recent issue of "The C++ Journal" shows how to do this example without using MI. -- Keith Gorlen phone: (301) 496-1111 Building 12A, Room 2033 FAX: (301) 402-0007 National Institutes of Health uucp: uunet!kgorlen%alw.nih.gov Bethesda, MD 20892 Internet: kgorlen@alw.nih.gov
bothner@sevenlayer.cs.wisc.edu (Per Bothner) (02/02/91)
In article <1991Jan31.164927.3234@odin.corp.sgi.com>, linton@sgi.com (Mark Linton) writes: >I would like to echo the original question, as I also have not encountered >a situation where I need non-virtual base classes. Perhaps it should be emphasized that even if one doesn't *need* non-virtual base classes, it may be reasonable to use them anyway for efficiency reasons. The main example is that of abstract base classes (or ones where the base class is otherwise "constant.") If one has a class hierarchy rooted in Object, it is undesirable to make Object a virtual base class, since it would add an extra indirection to *every virtual function call,* even for objects which only actually inherit from Object along a single path. -- --Per Bothner bothner@cs.wisc.edu Computer Sciences Dept, U. of Wisconsin-Madison
mjv@objects.mv.com (Michael J. Vilot) (02/08/91)
Keith Gorlen commented on my design decisions in the Booch Components library: >It seems to me that there is little, if any, advantage to using private >inheritance as opposed to simply including an instance of the class as a member >variable, I agree with Keith, and with Tom Cargill, that private base classes can be transformed into class members. There may be some minor performance differences between the two, but I suspect on average it's a wash. > Are there more compelling reasons for using private inheritance than this? Compelling? Probably not -- certainly not, in any absolute sense. Are there _compelling_ reasons for deriving all classes from a root class Object? Again, probably not. On the other hand, such decisions may make sense within a given set of design goals and constraints. Each decision represents a particular design choice. In my case, I used private derivation to express the difference between the abstract class and the ``concrete'' classes derived from it -- the derived classes mix in their representation. Making the representation class a private base separates it from the other members of the class, and highlights the design decision. |> The second use I made of MI was to mix in specific behavior for Node classes in |> the unbounded representations. >Is this also a case of private inheritance? No, in this latter case the derivation has to be public: Node classes mixing in Managed behavior (similarly for Shared) make the added members publicly available. The simplicity of the Managed and Controlled forms hinges on the transparent substitution of ``new'' and ``delete'' that occurs as a result. I'm looking forward to a lively discussion in Washington ! -- Mike Vilot, ObjectWare Inc, Nashua NH mjv@objects.mv.com (UUCP: ...!decvax!zinn!objects!mjv)
sdm@cs.brown.edu (Scott Meyers) (02/08/91)
In article <1174@zinn.MV.COM> mjv@objects.mv.com (Michael J. Vilot) writes: | I agree with Keith, and with Tom Cargill, that private base classes can be | transformed into class members. There may be some minor performance | differences between the two, but I suspect on average it's a wash. No no no. You lose virtual functions when you turn inheritance into member containment. There is a conceptual distinction between the following: A has a member B ==> A "has a" B (or A "contains a" B) A publicly inherits from B ==> A "is a" B A privately inherits from B ==> A "is implemented in terms of a" B Private inheritance is a convenient way to share code when there is no other conceptual relationship between two classes. I usually call this "code stealing." When stealing the code in another class, you often have to do some class specific stuff; this is where virtual functions come in. The member functions in the (private) base class can call virtual functions to do the customization. This won't work with member objects, because they have no way of knowing what they're a part of. | Each decision represents a particular design choice. In my case, I used | private derivation to express the difference between the abstract class and the | ``concrete'' classes derived from it -- the derived classes mix in their | representation. Making the representation class a private base separates it | from the other members of the class, and highlights the design decision. Right. Each derived class object "is an" abstract class object, hence public inheritance in that case. However, each derived class object "is implemented in terms of" an representation object, hence private inheritance. Scott ------------------------------------------------------------------------------- What do you say to a convicted felon in Providence? "Hello, Mr. Mayor."
kgorlen@alw.nih.gov (Keith Gorlen) (02/09/91)
In article <64173@brunix.UUCP>, sdm@cs.brown.edu (Scott Meyers) writes: |> In article <1174@zinn.MV.COM> mjv@objects.mv.com (Michael J. Vilot) writes: |> | I agree with Keith, and with Tom Cargill, that private base classes can be |> | transformed into class members. There may be some minor performance |> | differences between the two, but I suspect on average it's a wash. |> |> No no no. You lose virtual functions when you turn inheritance into member |> containment. There is a conceptual distinction between the following: |> |> A has a member B ==> A "has a" B (or A "contains a" B) |> A publicly inherits from B ==> A "is a" B |> A privately inherits from B ==> A "is implemented in terms of a" B |> |> Private inheritance is a convenient way to share code when there is no |> other conceptual relationship between two classes. I usually call this |> "code stealing." When stealing the code in another class, you often have |> to do some class specific stuff; this is where virtual functions come in. |> The member functions in the (private) base class can call virtual functions |> to do the customization. This won't work with member objects, because they |> have no way of knowing what they're a part of. |> That sounds like a good reason to me! -- Keith Gorlen phone: (301) 496-1111 Building 12A, Room 2033 FAX: (301) 402-0007 National Institutes of Health uucp: uunet!kgorlen%alw.nih.gov Bethesda, MD 20892 Internet: kgorlen@alw.nih.gov