cline@cheetah.ece.clarkson.edu (Marshall Cline) (08/22/90)
Suppose class A has a function f(), and class B also has a function f(). If C multiply inherits from A and B, then calling f() on a C is ambiguous. Supposedly (ARM section 10.1.1) explicit qualification (ex: A::f) can be used in C to disambiguate these f()'s. But suppose A::f() is virtual and B::f() is pure virtual: class A { public: virtual int f(); }; //A concrete class class B { public: virtual int f() = 0; }; //An abstract class class C : public A, public B { public: A::f; }; //A concrete class??? (This is not as obscure as it looks -- see below for a real-life example!) The rule for making a class non-abstract is that all pure virtuals need to be `filled in.' It seems reasonable that an explicit qualifier in C such as `A::f' fully specifies the definition of C::f(), so C ought NOT to be abstract. Unfortunately this doesn't appear to be the case in either g++ or Turbo-C++ (both seem to think that C is still abstract, as well as giving a pre-2.1 complaint to either implement each pure virtual or else re-declare them as pure virtual). The only thing I've been able to do is fully implement C::f() as calling B::f(). This gets old fast (especially when there are numerous member functions to be re-implemented) since it also adds an extra (fortunately non-virtual) function-call to each access. Any light? If this isn't already covered by the ARM (I didn't find it), I propose that the following `reasonable' behavior be accepted as correct: When class C has multiple public base classes A and B, with A::f() being a (non-pure) virtual and B::f() being a pure virtual, an explict qualification in C such as `A::f;' means that f() is NOT a pure virtual in C. Marshall Cline PS: Here's the scenario that got me into this mess (press 'n' if you're not interested...) A common C++'ism (at least in my code!) is to hang several alternate implementations of a `concept' from an abstract base class (ABC). Ex: Stack (ABC) / \ VStack LStack etc etc (Vector-based) (List-based) Now consider an `Invertable Stack' as a specialized Stack, and suppose (rather than retrofitting an `invert()' member into each Stack class) you want a separate hierarchy. That's easy: create an InvStack ABC which inherits from the Stack ABC. There's no reason to prevent someone from implementing VInvStack (the vector based InvStack) by inheriting from VStack, which leads to multiple inheritance: Stack (ABC) | \________ | \ | InvStack | (ABC) VStack | \______ | \ | VInvStack I don't want to argue whether you *need* MI in this example -- clearly VInvStack can *contain* a VStack (at the cost of reimplementing all the member functions), or could *privately* derive from VStack (at the cost of specifying the access of all VStack member functions as public). I just think the above is a natural and convenient strategy, since reusing the VStack implementation means you only have to implement the orthogonally added function `invert()'. Furthermore note that `push()', `pop()', etc, will be pure virtual in InvStack simply by reason of the fact that they were inherited as pure virtual from Stack (this is a new rule in 2.1). *However* VInvStack will also inherit the *implemented* `push()', `pop()', etc, from VStack. QUESTION: How can I convince the compiler to use VStack's implementation of `push()'?? Neither GNU C++ nor Turbo-C++ accept explicit qualification (ex: `VStack::push;') in the public section of VInvStack (when I try to instantiate a VInvStack, both complain that I never gave an implementation of a pure virtual). The only thing I've been able to do is re-implement each member function so it calls the VStack version. This is unacceptable since it not only costs me implementation (and maintenance) time, it also costs an extra (fortunately non-virtual) function call for each access. -- ============================================================================== Marshall Cline / Asst.Prof / ECE Dept / Clarkson Univ / Potsdam, NY 13676 cline@sun.soe.clarkson.edu / Bitnet:BH0W@CLUTX / uunet!clutx.clarkson.edu!bh0w Voice: 315-268-3868 / Secretary: 315-268-6511 / FAX: 315-268-7600 Career search in progress; ECE faculty; research oriented; will send vita. PS: If your company is interested in on-site C++/OOD training, drop me a line! ==============================================================================
mjv@objects.mv.com (Michael J. Vilot) (08/24/90)
Marshall Cline describes a problem with multiple inheritance: > an explicit qualification ... means that f() is NOT a pure virtual This is actually a specific instance of a more general problem. Section 10.11c in E&S mentions the topic of ``Renaming'' and the problem of finding an appropriate way to express the semantics of merging names from multiple base classes. The status of inherited virtuals is similar. Bjarne's current proposal for ``Overriding'' (the topic's been Renamed ;-) addresses these concerns. > A common C++'ism One more vote to make it ``common'' -- this is exactly the approach we used in The C++ Booch Components library. Our paper at the ECOOPSLA conference presents the design. I'm looking forward to next month's presentation of Annotated C++, I think it's important work. -- Mike Vilot, ObjectWare Inc, Nashua NH mjv@objects.mv.com (UUCP: ...!decvax!zinn!objects!mjv)