[comp.lang.c++] C++ multiple inheritance

james@utastro.UUCP (James McCartney) (06/18/88)

   I just saw a posting in comp.sys.mac.programmer for a 3 day talk on MPW C++
that included a discussion on multiple inheritance & virtual classes in C++.
It also says that C++ has a very efficient run time implementation of mult-
iple inheritance.
   I didn't think C++ had multiple inheritance. I've heard that there is a 
paper by Bjarne Stroustup on mult. inher. Could someone illuminate me on how
mult. inher. can/could be done in C++. I know it can be worked around with
friends and the like. What IS a virtual class and what is it for?
--- James McCartney

mikem@otc.oz (Mike Mowbray) (06/21/88)

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

cmc@inf.rl.ac.uk (Chris Crampton) (07/11/88)

In article <401@otc.oz> mikem@otc.oz (Mike Mowbray) writes:
>...
>This would tend to imply that future library designers should always use
>virtual bases unless they have a very good reason not to.

Indeed, if a library is to be truly extensible then it seems to me that
the designers should make all methods and destructors virtual unless they
have a good reason not to. Another tough decision for library designers
is which methods (and possibly data) should be made protected instead of
private. Bad decisions made early on can make things very difficult for
programmers who are sub-classing rather than just using the existing
classes. 

I sometimes wish that virtual were the default...

Chris.

=======================================================================
Chris M Crampton		UK JANET:   cmc@uk.ac.rl.inf
Rutherford Appleton Labs,	ARPA:	    cmc%inf.rl.ac.uk@nss.cs.ucl.ac.uk
Didcot, OXON, U.K.		UUCP:	    ..!mcvax!ukc!rlvd!cmc
+44 235 21900   ext. 6756		    cmc@rlvd.uucp