Path: utzoo!utgpu!news-server.csri.toronto.edu!mailrus!uunet!cs.utexas.edu!usc!apple!sun-barr!newstop!sun!morocco!landauer From: landauer@morocco.Sun.COM (Doug Landauer) Newsgroups: comp.lang.c++ Subject: Re: Pointers and Multiple Inheritance Message-ID: <134400@sun.Eng.Sun.COM> Date: 12 Apr 90 20:38:36 GMT References: <6170015@hpindda.HP.COM> Sender: news@sun.Eng.Sun.COM Reply-To: landauer@sun.UUCP (Doug Landauer) Organization: Sun Microsystems, Mountain View Lines: 89 > 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 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."