This is our ideal inheritance hierarchy:
class Foobar;
class FoobarClient : Foobar;
class FoobarServer : Foobar;
class WindowsFoobar : Foobar;
class UnixF
Have a look at this search. Diamond inheritance is somewhat of contentuous issue and the proper solution dependes on individual situation.
I would like to comment on the Unix/Windows side of things. Generally one would #ifndef
things out that are not appropriate for the particular platform. So you would end up with just Foobar
compiled for either Windows or Unix using preprocessor directives, not UnixFoobar
and WindowsFoobar
. See how far you can get using that paradigm before exploring virtual inheritance.
You can access the variable with the qualified class name, but I forget the exact syntax.
However, this is one of the bad cases of using multiple inheritance that can cause you many difficulties. Chances are that you don't want to have things this way.
It's much more likely you want to have foobar privately inherited, have each subclass own a foobar, have foobar be a pure virtual class, or have the derived class own the things it currently defines or even define foobar on its own.
What you are directly after here is virtual inheritance feature of C++. What you are in here for is a maintenance nightmare. This might not be a huge surprise since well-known authors like H. Sutter have been arguing against such use of inheritance for a while already. But this comes from direct experience with code like this. Avoid deep inheritance chains. Be very afraid of the protected
keyword - it's use is very limited. This kind of design quickly gets out of hand - tracking down patterns of access to protected variable somewhere up the inheritance chain from lower level classes becomes hard, responsibilities of the code parts become vague, etc., and people who look at your code a year from now will hate you :)
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.
Use virtual inheritance, in the declaration of FoobarClient
, FoobarServer
, WindowsFoobar
and UnixFoobar
, put the word virtual
before the Foobar
base class name.
This will ensure there is always a single instance of Foobar
no matter how many times it appears in your base class hierarchy.
Try this example of composition and inheritance:
class Client_Base;
class Server_Base;
class Foobar
{
Client_Base * p_client;
Server_Base * p_server;
};
class Windows_Client : public Client_Base;
class Windows_Server : public Server_Base;
class Win32 : Foobar
{
Win32()
{
p_client = new Windows_Client;
p_server = new Windows_Server;
}
};
class Unix_Client : public Client_Base;
class Unix_Server : public Server_Base;
class Unix : Foobar
{
Unix()
{
p_client = new Unix_Client;
p_server = new Unix_Server;
}
};
Many experts have said that issues can be resolved with another level of indirection.