Path: utzoo!attcan!uunet!munnari!otc!mikem From: mikem@otc.oz (Mike Mowbray) Newsgroups: comp.lang.c++ Subject: Re: C++ multiple inheritance Message-ID: <401@otc.oz> Date: 21 Jun 88 11:39:32 GMT References: <2786@utastro.UUCP> Organization: OTC Development Unit, Australia Lines: 109 In article <2786@utastro.UUCP>, james@utastro.UUCP (James McCartney) says: > Could someone illuminate me on how mult. inher. can/could be done in C++. It can be done by an extension of the single inheritance mechanism. (Needs a new cfront of course.) The main problem is how to handle virtual member functions. E.g: class Male { public: virtual be_impotent(); // something specific to Males }; class Female { public: virtual have_period(); // something specific to Females }; class Hermaphrodite : public Male, public Female { public: be_impotent(); // Let's assume hermaphrodites have their // own form of impotency have_period(); // and that they have periods differently. }; Now consider: main() { Hermaphrodite h; Male *m = &h; Female *f = &h; m->be_impotent(); f->have_period(); } At the point where m->be_impotent() is called, cfront only knows that it's got a ptr to Male. But Hermaphrodite::be_impotent() expects a "this" which is a ptr to Hermaphrodite. In the single inheritance case, there is no difficulty, since the address of one is the address of the other. But in the multiple inheritance case there are different sub-objects like: struct _Hermaphrodite { // Male stuff struct _Female OFemale; }; The solution is to extend the vtbl's associated with each class to include offsets. I.e: instead of just being a table of pointers to functions, they're a table of pairs (pointer-to-fn, delta). So when a virtual member is invoked, you get something like: (*object->vptr[1].f)(((char*)&object) + object->vptr[1].delta , .....); > What IS a virtual class and what is it for? Ah. Virtual base classes are truly marvellous things. In ordinary MI, if a base class is a multiple grandparent, there are multiple sub-objects. E.g: class LinkItem { ... }; class A : public LinkItem { .... }; class B : public LinkItem { .... }; class Both : public A, public B {....}; Here class Both can simultaneously be on a list of A's and a list of B's, since its A and B sub-objects have separate LinkItem sub-objects. There are case, however, when one would like the grandparent sub-objects to be the same instance (i.e: shared or common). For example: class CommonData { protected: int i; } class A : virtual public Common { .... }; class B : virtual public Common { .... }; class Both : virtual public A, virtual public B { .... }; Here, if a member of A modifies CommonData::i, a member function of B will see the modification. (Unlike the non-virtual MI case above). This mechanism takes some skill to use reliably, especially within libraries, but is very nice. Think about it. Someone can write the A and B classes above, and someone else can write the "Both" class even if he only has object code for the CommonData, A and B classes. He thereby obtains an interaction between A and B through the common sub-object. Naturally the documentation of the behaviour of A and B needs to be very complete to do this confidently, and the original designer of A and B ought probably to have borne virtual base classes in mind. Even given these caveats, it's a very nice way to combine library classes when you don't have the source code. This would tend to imply that future library designers should always use virtual bases unless they have a very good reason not to. Mike Mowbray Systems Development |||| OTC || ACSnet: mikem@otc.oz TEL: (02) 287-4104 UUCP: {seismo,mcvax}!otc.oz!mikem SNAIL: GPO Box 7000, Sydney, Australia