Hello everyone!
I am a newbie to C++ (~1 Week experience) and I have a few months of
experience with object-oriented languages (Objective-C). I am
currently working just for fun on a particle system.
All the particles are controlled by a "server". The server performs
all kinds of operations on them (updating, drawing etc.). The
particles (my "clients") on the other hand need to retrieve once a
while some information from their server - they need to be hooked up
to it. This works perfectly alright as long as I only have one
server-class and one client-class. However if I want to add some
subclasses and make everything more customizable I run into severe
problems. The lack of run-time dynamism caused some problems on
creating the server/client class structure.
If I use a new client-class it will most likely need a new
server-class. However its superclass already inherits a connection to
the old server-class. I would need to re-implement all the member
functions for the new server-class. In a pure dynamic language
(Smalltalk/Objective-C) I could simply ignore the static type
checking. To avoid compiler warnings I would simply cast the
object-pointers when necessary (just for cosmetic reasons).
C++ would not be C++ if it wouldn't deliver a solution for this
dilemma - Templates. When I need a new client class, I just need to
pass a new type parameter. Nice.
And C++ wouldn't be C++ if no new problems would arise. I will
demonstrate it.
My server-class implementations:
template <class GenericClient>
class ServerClass
{
public:
ServerClass()
{
clients = vector<GenericClient> (10, GenericClient(*this));
}
protected:
vector<GenericClient> clients;
int foo;
};
template <class GenericClient>
class ServerSubclass : public ServerClass<GenericClient>
{
public:
ServerSubclass() {}
protected:
int bar;
};
No problem until now. But now the client-class implementations:
template <class GenericServer>
class ClientClass
{
public:
ClientClass() : server(NULL) {}
ClientClass(GenericServer *aServer) { server = aServer; }
protected:
GenericServer *server;
};
template <class GenericServer>
class ClientSubclass : public ClientClass<GenericServer>
{
public:
ClientSubclass() {}
ClientSubclass(GenericServer *aServer) :
ClientClass<GenericServer>(aServer){}
protected:
int bla;
};
You can see that every client gets a connection to its server, when it
is constructed. But now try to instantiate a server with a
client-class.
ServerSubclass<ClientSubclass<ServerSubclass<Clien tSubclass...> > >
We get an infinite circular dependency between the template classes.
It is impossible to solve this circular dependency unless I have
missed something fundamental about C++ templates.
However there is a not so elegant way to do it with partially
resorting to traditional OO constructions. All I need to do is to
rewrite my client-subclass without templates.
class ClientSubclass : public
ClientClass<ServerSubclass<ClientSubclass> >
{
public:
ClientSubclass() {}
ClientSubclass(ServerSubclass<ClientSubclass> *aServer) :
ClientClass<ServerSubclass<ClientSubclass> >(aServer) {}
protected:
int bla;
};
This looks confusing and it is indeed. But it is now possible to
instantiate a server.
ServerSubclass<ClientSubclass> myServer();
However subclassing without a template is not only a way to solve the
circular-dependency-problem but also to prevent any further
subclassing. If I wanted to subclass my first-subclass with all its
member functions I would need to convert my first subclass to a
template class and then subclass it twice (once for the first and once
for the second non-template subclass).
Am I totally wrong? Have I totally missed something about OO design?
Is there a more convenient way of doing this in C++ ?
Any comments appreciated ;-)
TIA
Robert Potthast