Topic: Naming clashes for virtual functions and multiple inheritance
Author: "Bradd W. Szonye" <bradds@ix.netcom.com>
Date: 1996/09/04 Raw View
Trevor Yann <ty@kodak.com.au> wrote in article
<322B6466.7FBE@kodak.com.au>...
> I would like to know whether a particular limitation with multiple
inheritance
> exists in the current draft of the standard.
>
> Virtual functions with the same name and signature in different base
classes must
> have identical semantics. This problem is solved in the language Eiffel,
which
> requires that any member functions declared in base classes with names
that clash
> must be renamed.
I'm not sure what you mean by "must have identical semantics." Virtual
functions with the same name and (compatible) signatures are ambiguous
under MI. The usual workaround is to hide the base class functions that
clash with a new function that overrides both base-class functions or at
least forwards to the right one.
> Example: implementation of OLE (or CORBA?) interfaces.
[example of this problem with OLE interfaces and MI]
> There is no inheritance between the interfaces Cat1 and Cat2, because
there is a
> method removed. It is intended that eventually the Cat1 interface will
no longer
> supported. The Cat1 interface cannot be modified - it has already been
published
> and changes would break client code.
> There is no way to determine in CatImplementation1::purr() whether this
is for
> the Cat1 or Cat2 interface. The behaviour could have changed.
If the implementation of "purr" semantics are similar enough, you can write
a forwarding override in the new derived class that merely forwards its
behavior to the "newer" function in Cat2. If you really need to determine
which interface to use, then the appropriate idiom is not MI but nested
interface classes.
> One solution is to do something like:
[example of conflicting interfaces implemented with nested classes]
The nested-class solution for OLE interfaces is the standard one, as noted
by Brockschmidt in "Inside OLE." Implementing interfaces through
inheritance only works well for fairly simple OLE interfaces that don't
interfere with each other. This "workaround" lets you use pointers to the
nested classes for your interfaces; the nested classes forward to the
containing object for actual behavior. Determining which behavior to use is
part of the forwarding function.
> Does the language defined by the current draft of the standard provide a
means
> for avoiding some of the working required for something like
Cat2Implementation?
I don't think there's any need for an ANSI/ISO standard on this issue when
there's already a Microsoft implementation standard: that is, using nested
classes instead of MI. In fact, I rather like the notion of actually having
"interface objects" which are components that determine the interface to a
"behavior object." It's a different idiom, that's all, and one which offers
more flexibility and control than MI does, at the cost of only a small
increase in complexity and overhead.
--
Bradd W. Szonye
bradds@ix.netcom.com
http://www.netcom.com/~bradds
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: Trevor Yann <ty@kodak.com.au>
Date: 1996/09/02 Raw View
I would like to know whether a particular limitation with multiple inheritance
exists in the current draft of the standard.
Virtual functions with the same name and signature in different base classes must
have identical semantics. This problem is solved in the language Eiffel, which
requires that any member functions declared in base classes with names that clash
must be renamed.
Example: implementation of OLE (or CORBA?) interfaces.
An object might implement any number of interfaces, including multiple revised
interfaces:
class Cat1
{
public:
virtual void purr();
virtual void bark();
};
class Cat2
{
public:
virtual void purr();
virtual void eat();
};
class CatImplementation1: public virtual Cat1, public virtual Cat2
{
// implementation
};
There is no inheritance between the interfaces Cat1 and Cat2, because there is a
method removed. It is intended that eventually the Cat1 interface will no longer
supported. The Cat1 interface cannot be modified - it has already been published
and changes would break client code.
There is no way to determine in CatImplementation1::purr() whether this is for
the Cat1 or Cat2 interface. The behaviour could have changed.
One solution is to do something like:
class CatImplementation2
{
class Cat1Implementation: public virtual Cat1
{
};
class Cat2Implementation: public virtual Cat2
{
};
Cat1Implementation cat1;
Cat2Implementation cat2;
void purr1();
void purr2();
};
where Cat1Implementation and Cat2Implementation forward messages appropriately to
the enclosing Cat2Implementation2 object. This allows separate implementation of
purr(). CatImplementation2 is a fairly convoluted compared to CatImplementation1
- there is substantial work to be done working around language limitations before
the real implementation can be done.
Does the language defined by the current draft of the standard provide a means
for avoiding some of the working required for something like Cat2Implementation?
Trevor Yann
ty@kodak.com.au
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]