Если вы действительно не хотите использовать виртуальные функции (на самом деле это идеальный вариант их использования, но я не знаю о ваших классах сообщений), вы можете использовать CRTP :
template <typename U>
struct Consumer
{
template <typename T>
void callback(T msg)
{ static_cast<U*>(this)->callback(msg); }
};
struct Client : Consumer<Client>
{
void callback(Msg1 msg);
void callback(Msg2 msg);
void callback(Msg3 msg);
};
Проблема, конечно, в том, что вы не можете больше хранить Consumer
объекты в контейнере.Поскольку все время компиляции, фактический тип клиента должен храниться рядом с объектом-потребителем, чтобы компилятор вызывал правильную функцию обратного вызова.Виртуальные функции позволяют вам ждать до времени выполнения для этого ...
Есть ли причина, по которой классы Msg
не полиморфны и не используются стандартные виртуальные функции (кроме "Я должен переписать весь код и не могу")?
EDIT Если вы беспокоитесь о классах сообщений, почему бы не использовать что-то подобное, если предположить, что классы сообщений реализуют функцию-член DoSomething
: (этот метод известен как Введите Erasure )
struct AnyMsg
{
template <typename Msg>
AnyMsg(Msg x) : impl(newImpl(x)) {}
void DoSomething() { impl->DoSomething(); }
private:
struct Impl
{
virtual ~Impl() {}
virtual void DoSomething() = 0;
};
// Probably better is std::unique_ptr if you have
// C++0x. Or `boost::scoped_ptr`, but you have to
// provide copy constructors yourself.
boost::shared_ptr<Impl> impl;
template <typename Msg>
Impl* newImpl(Msg m)
{
class C : public Impl
{
void DoSomething() { x.DoSomething(); }
Msg x;
public:
C(Msg x) : x(x) {}
};
return new C(m);
}
};
Вы можете настроить поведение newImpl
, чтобы получить то, что вы хотите (например, действия по умолчанию, если в классе сообщений нет функции-члена DoSomething
, специализациядля некоторых классов сообщений или чего-либо еще).Таким образом, вы реализуете Msg
классы, как если бы вы использовали свое шаблонное решение, и у вас есть уникальный фасад, который вы можете передать виртуальным функциям в ваших клиентских классах.
Если классы Message собираютсябыть очень разными, и клиентские классы могут по-разному реагировать на них, и у вас будет много классов сообщений, это начинает пахнуть.Или, возможно, у вас есть кандидатура на уродливый и страшный шаблон Visitor .