Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using C++, how do I correctly inherit from the same base class twice?

This is our ideal inheritance hierarchy:

class Foobar;

class FoobarClient : Foobar;

class FoobarServer : Foobar;

class WindowsFoobar : Foobar;

class UnixFoobar : Foobar;

class WindowsFoobarClient : WindowsFoobar, FoobarClient;

class WindowsFoobarServer : WindowsFoobar, FoobarServer;

class UnixFoobarClient : UnixFoobar, FoobarClient;

class UnixFoobarServer : UnixFoobar, FoobarServer;

This is because the our inheritance hierarchy would try to inherit from Foobar twice, and as such, the compiler would complain of ambiguous references on any members of Foobar.

Allow me to explain why I want such a complex model. This is because we want to have the same variable accessible from WindowsFoobar, UnixFoobar, FoobarClient, and FoobarServer. This wouldn't be a problem, only I'd like to use multiple inheritance with any combination of the above, so that I can use a server/client function on any platform, and also use a platform function on either client or server.

I can't help but feel this is a somewhat common issue with multiple inheritance... Am I approaching this problem from completely the wrong angle?

Update 1:

Also, consider that we could use #ifdef to get around this, however, this will tend to yield very ugly code like such:

CFoobar::CFoobar()
#if SYSAPI_WIN32
: m_someData(1234)
#endif
{
}

... yuck!

Update 2:

For those who want to read more into the background of this issue, I really suggest skimming over the appropriate mailing list thread. Thing start to get interesting around the 3rd post. Also there is a related code commit with which you can see the real life code in question here.

like image 503
Nick Bolton Avatar asked Jan 01 '10 23:01

Nick Bolton


1 Answers

It would work, although you'd get two copies of the base Foobar class. To get a single copy, you'd need to use virtual inheritance. Read on multiple inheritance here.

class Foobar;

class FoobarClient : virtual public Foobar;

class FoobarServer : virtual public Foobar;

class WindowsFoobar : virtual public Foobar;

class UnixFoobar : virtual public Foobar;

However, there are many problems associated with multiple inheritance. If you really want to have the model presented, why not make FoobarClient and FoobarServer take a reference to Foobar at construction time, and then have Foobar& FoobarClient/Server::getFoobar ?

Composition is often a way out of multiple inheritance. Take a example now:

class WindowsFoobarClient : public WindowsFoobar 
{
    FoobarClient client;
public:
    WindowsFoobarClient() : client( this ) {}
    FoobarClient& getClient() { return client }
}

However care must be taken in using this in the constructor.

like image 158
Kornel Kisielewicz Avatar answered Sep 21 '22 16:09

Kornel Kisielewicz