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."