Path: utzoo!mnetor!tmsoft!torsqnt!news-server.csri.toronto.edu!cs.utexas.edu!wuarchive!zaphod.mps.ohio-state.edu!sol.ctr.columbia.edu!ira.uka.de!smurf!nadia!ananke!kaiser From: kaiser@ananke.stgt.sub.org (Andreas Kaiser) Newsgroups: comp.lang.c++ Subject: help! with multiple inheritance Message-ID: <34.276F3438@ananke.stgt.sub.org> Date: 19 Dec 90 09:32:49 GMT Organization: Ananke, Stuttgart, FRG Lines: 67 In a message of , Joel Spolsky (spolsky-joel@CS.YALE.EDU ) writes: JS> class Tiger { JS> public: JS> virtual void Roar (void) JS> {printf("roar\n");} JS> }; JS> class Senegal: public b, public Tiger{ JS> public: JS> virtual void Roar (void) JS> {printf("senegal roar\n");} JS> }; Consider the implementation of Senegal: Since it has two base classes, at least one of those has a non-zero offset within the derived class. Since typically the first has zero offset (but don't rely on this fact, sinceimplementations may vary), the base class Tiger has not. JS> main() JS> { JS> Senegal *ps = new Senegal; JS> // This works, printing "senegal roar": JS> printf("cast to Tiger *:\n"); JS> ((Tiger *) ps)->Roar(); The compiler recognizes that Tiger is a base class of your object of type Senegal and converts the pointer by adding the offset mentioned above. JS> // This segment faults: JS> printf("cast thru:\n"); JS> ((Tiger *) (void *) ps)->Roar(); But now the compiler does not know anything aboid the pointer, since it is a void pointer. So the cast is in effect s noop and does not add or subtract a constant. Try printf ("%p %p\n", (Tiger *) ps, (Tiger *) (void *) ps); and you'll see the difference. In the case of single inheritance, the offset typically is zero, so both are the same and program works. But you hit a point. This is a real problem in C++. Until the day when templates are implemented in most available compilers, void pointers have to be used in some circumstances. Maybe this problem is the reason, why Bjarne Stroustup left the implicit conversion TO (void *), but removed the implicit conversion FROM (void *) from the language. Type casts are not necessarily transitive operations. Hint: replace (Tiger *) (void *) ps by (Tiger *) (void *) (Tiger *) ps - If you have a program, where a (void *) is converted to (A *) before use, always carry out the conversion to (A *) BEFORE converting to (void *). - Always make sure, that the conversion to and from some pointer type converts between exactly the same types. - Do not allow a cast to and from some type to carry out an implicit third conversion (in your example: (Tiger *) ps). Andreas