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