linton@sgi.com (Mark Linton) (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. The case you refer to is pretty pathological. I'll use the names Base and Derived instead of your B and A. Since Derived privately inherits from Base, the only place you can call a Base method from a Derived object is in Derived itself. Then Base::method calls a virtual on Base that Derived redefines and you end back in a Derived method. Example code is: class Base { virtual void f(); void g(); }; class Derived : private Base { virtual void f(); void h(); }; void A::f() { } void A::g() { shared_before_stuff(); f(); shared_after_stuff(); } void B::f() { ... } void B::h() { g(); } Note that B::f() can't be called directly (except from another B method, of course). You refer to private inheritance as "convenient", but I have never needed the circular control flow above. We don't use it at all in InterViews (about 100K lines of C++). Most examples of code sharing I have seen are better implemented with either separate types or templates (or the macro equivalent). If you have a real example of "convenient" private inheritance, I'd be interested in seeing it.
chip@tct.uucp (Chip Salzenberg) (02/13/91)
According to linton@sgi.com (Mark Linton): > If you have a real example of "convenient" private inheritance, > I'd be interested in seeing it. In a real application I have two classes, SqlStmt and SqlCursor. SqlStmt is a private base class of SqlCursor. I would have made it public, but to maintain internal consistency I can allow only one member function of SqlStmt public, namely, SqlStmt::in(). However, SqlStmt::in() is actually several overloaded functions. Thus the declaration: class SqlCursor : private SqlStmt { public: SqlCursor(); ~SqlCursor(); SqlStmt::in; // other declarations... }; This declaration conveniently makes all the SqlStmt::in() functions public without needing to name them all. The use of inheritance instead of a SqlStmt member variable also implies that the member functions of SqlCursor can call member functions of SqlStmt without specifying "member.func()". Both of these aspects are convenience wins. -- Chip Salzenberg at Teltronics/TCT <chip@tct.uucp>, <uunet!pdn!tct!chip> "I want to mention that my opinions whether real or not are MY opinions." -- the inevitable William "Billy" Steinmetz