[comp.lang.c++] Pointers and Multiple Inheritance

daver@hpindda.HP.COM (Dave Richards) (04/10/90)

This is probably a trivial question, but I've been hunting through my
documentation and can't find it...

Given a pointer to an instance of a single-inherited subclass, it is
legal to cast that pointer to any of the instance's superclasses.  However,
given an instance of a multiply-inherited class is it legal to cast that
pointer to any of the inherited superclasses?  I would say not.  What
then, can a pointer to a multiply-inherited class be cast to?

	Dave Richards

jimad@microsoft.UUCP (Jim ADCOCK) (04/13/90)

In article <6170015@hpindda.HP.COM> daver@hpindda.HP.COM (Dave Richards) writes:
>This is probably a trivial question, but I've been hunting through my
>documentation and can't find it...

Neither could I, when I went looking for it....

>Given a pointer to an instance of a single-inherited subclass, it is
>legal to cast that pointer to any of the instance's superclasses.  

Yes, this is true.

>However given an instance of a multiply-inherited class is it legal to cast 
 that pointer to any of the inherited superclasses?  I would say not.  

Wrong guess, this is legal too, if I correctly understand your question.  
Given class FOOBAR multiply inheriting from FOO and BAR, a FOOBAR* can
be cast, either explicetly or implicetly, to either a FOO* or a BAR*

C++ compilers are smart enough to correctly do the pointer offsets.
Pointer coercions in C++ are not longer necessarily conceptual, but
can actually change the bit representations of the pointers involved.
But this was always [potentially, at least] true of C implementations too.

--If your derivations are private, you can still do all these pointer
coercions, but the pointer coercions must be explicet, not implicet.

>What then, can a pointer to a multiply-inherited class be cast to?

Implicetly, to any of its superclasses.  Explicetly, to almost anything.
The only restriction I can think of is in some instances of virtual
base classes.  These are the situations where the virtual base class is
handled via delegation.

Note:  Just 'cuz its "legal" to do these things doesn't necessarily
mean its "good" to so.

landauer@morocco.Sun.COM (Doug Landauer) (04/13/90)

> Given a pointer to an instance of a single-inherited subclass, it is
> legal to cast that pointer to any of the instance's superclasses.  However,
> given an instance of a multiply-inherited class is it legal to cast that
> pointer to any of the inherited superclasses?  I would say not.  What
> then, can a pointer to a multiply-inherited class be cast to?

Let's try to ask this question using terms familiar to C++ programmers
who're uncomfortable with Smalltalk (i.e., replace jargon with patois,
or lingo with argot  :> ):

=> Given a pointer to a variable of a single-inherited derived class, it is
=> legal to cast that pointer to any of its class's base classes.  However,
=> given a variable of a multiply-inherited class is it legal to cast that
=> pointer to any of the inherited base classes?

The quick answer is "yes".  However, this isn't quite the point that
most people have trouble with.  It's not just that it's legal for you
to do such a cast *explicitly*, but you can also do it *implicitly*,
which can be a bit more subtle, and can be surprising until you think
it over for a while.

> What then, can a pointer to a multiply-inherited class be cast to?

Well, lots of things, *explicitly*.  Remember that a cast is a
deliberate circumvention of the type system.  Often, people will take a
pointer to a base class, and cast it to the derived class (for example,
while reconstructing objects that have just been read in from
persistent storage).  Note that this is the dangerous direction to go,
and you should only do this when you know for sure what type you really
have.  One form of this that is still not allowed is to take a
pointer to a base class and cast it to be a pointer to a class that
derives virtually from it -- you can't follow a pointer backwards, even
if you ask nicely.

Perhaps we should re-ask these questions using terms familiar to C++
programmers who're uncomfortable with (English) words (especially the
overloading of the word "to" in phrases like "cast ... to ..." versus
"a pointer to ...").   So here's the question -- your C++ system may
or may not have an answer:
 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
#include <stream.h>
struct b1 { virtual void print(); };
struct b2 { virtual void print(); };

void b1::print() { cout << "b1\n" ; }
void b2::print() { cout << "b2\n" ; }

struct dsing : b1 { void print( ) { cout << "dsing\n"; } };
struct ddub : b1, b2 { void print( ) { cout << "ddub\n"; } };
struct ddvirt : virtual b1, virtual b2 {
	void print( ) { cout << "ddvirt\n"; }
};

main ( ) {
    dsing *d1p = new dsing; d1p->print( );

    b1 * b1p = d1p;	// your single-inheritance cast can be implicit.
    b1p->print( );	// it's still a dsing
    b1 b1v = *b1p;	// You can even do this implicit cast with variables
			// instead of just pointers.  But this chops off the
			// derived bits as we copy just the b1 part of the
			// dsing into (becoming) a b1.
    b1v.print( );	//	should print "b1"

    // d1p = b1p;	// error -- cannot implicitly cast this direction,
    d1p = (dsing *)b1p;	// but it's ok with an explicit cast

    ddub *ddp = new ddub;  ddp->print( );

    b1 * bd1p = ddp; bd1p->print( );	// implicit casts to M-I bases
    b2 * bd2p = ddp; bd2p->print( );	// are OK ...

    ddvirt *dvp = new ddvirt;  dvp->print( );

    b1 * bv1p = dvp; bv1p->print( );	// ... even if they're virtual.
    b2 * bv2p = dvp; bv2p->print( );

    // Casting back to derived is still allowed, though dangerous:
    ddub *castback = (ddub*)bd1p ;	// still OK with a cast
    castback->print( );

    // BUT you can't follow a pointer backwards, even if you ask nicely:
    ddvirt *castback_v = (ddvirt*)bd1p;	// not OK, even with a cast
	// line XX: error: cast: b1* ->derived ddvirt*; b1 is virtual base
}
// Hope this helps explain things ... a bit more explicitly.
//
// Doug Landauer - Sun Microsystems, Inc. - Languages - landauer@eng.sun.com
//     Matt Groening on C++:  "Our language is one great salad."