Лучше всего это сделать, используя политику для транспортного протокола:
template<typename Transport>
class service : Transport {
public:
typedef Transport transport_type;
// common code
void do_something() {
this->send(....);
}
};
class tcp {
public:
void send(....) {
}
};
class udp {
public:
void send(....) {
}
};
typedef service<tcp> service_tcp;
typedef service<udp> service_udp;
Обратите внимание, что это также полиморфно. Это называется полиморфизмом времени компиляции. Помещение политики в базовый класс выиграет от оптимизации пустого базового класса. То есть вашему базовому классу не нужно занимать никакого пространства. Помещение политики в качестве члена имеет другой недостаток, заключающийся в том, что вы всегда должны делегировать вещи этому члену, что со временем может раздражать. Книга Современный дизайн C ++ подробно описывает этот паттерн.
В идеале транспортному протоколу не нужно ничего знать о протоколе над ним. Но если по какой-то причине вам необходимо получить некоторую информацию об этом, вы можете использовать шаблон crtp wiki :
template<template<typename Service> class Transport>
class service : Transport<service> {
// since we derive privately, make the transport layer a friend of us,
// so that it can cast its this pointer down to us.
friend class Transport<service>;
public:
typedef Transport<service> transport_type;
// common code
void do_something() {
this->send(....);
}
};
template<typename Service>
class tcp {
public:
void send(....) {
}
};
template<typename Service>
class udp {
public:
void send(....) {
}
};
typedef service<tcp> service_tcp;
typedef service<udp> service_udp;
Вам не нужно помещать ваши шаблоны в заголовки. Если вы явно создадите их экземпляр, вы получите более быстрое время компиляции, так как необходимо включить намного меньше кода. Поместите это в service.cpp:
template class service<tcp>;
template class service<udp>;
Теперь код, который использует службу, не должен знать о коде шаблона службы, поскольку этот код уже сгенерирован в объектном файле service.cpp.