views:

232

answers:

1

Let's say I have a simple Server with a template which accepts a Client as it's template argument:

template<class T>
class Server<T>{
    Server(int port);
}

and a Client is defined something like this:

class Client{
    Client(Server<Client> *server, // <--
           int socket);
};

But I also want say, have the class User inherit from Client (class User : public Client), so I could do Server<User> instead of Server<Client>. class User obviously needs to pass Server<Client> as a parameter when constructing Client. However, with the current implementation this seems impossible.

How should I approach this problem?

+4  A: 

What about this?

template<class T>
class Server<T>{
    Server(int port);
};

template<class Derived>
class Client {
    Client(Server<Derived> *server, int socket);
    virtual ~Client() {} // Base classes should have this
};

class User : public Client<User> {
};
Dario
Required some refactoring of existing code, but this was essentially what I wanted. Great thanks!
Chaosteil
Actually, the destructor would probably be better to be protected and non-virtual. This design almost certainly doesn't want people deleting instances of User through a `Client<User> *`.
Steve Jessop
@onebyone: Why not?
rstevens
Note that this is known as CRTP: http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern
sbi
@rstevens: because in order to even have a `Client<User>` pointer, they have to know that the object is in fact a `User`, not just some generic `Client`. So why wouldn't they just have a pointer to `User`? This pattern means that there is no common base class for all the different client "subclasses": `Client<User1>` and `Client<User2>` are unrelated. So runtime polymorphism is not appropriate. If the `Client` class template specified a non-template public base, `ClientBase`, then we'd be back to a common base class, and then sure, `ClientBase` could/should have a virtual destructor.
Steve Jessop
"why wouldn't they just have a pointer to User" - actually there is an answer to that, which is they might be doing something template-y themselves, and somehow be lumbered with the essentially useless Client<User> type as a template parameter more-or-less by accident. If this can't be fixed, and they absolutely have to delete through that type because they can't cast to `User*`, then I suppose you might let them. In general, though, I write C++ with runtime polymorphism not supported by default. Gives you more freedom to do useful C++-ish things, like using standard containers of values.
Steve Jessop