3.8Kпросмотров
40.9%от подписчиков
25 февраля 2026 г.
Score: 4.2K
CRTP + friend
#опытным Допустим, вам нужно написать tcp и udp версии клиента для одной и той же задачи. Можно использовать динамический полиморфизм и переопределить все специфические методы. Но тогда у нас будет оверхед на динамическую диспетчеризацию вызова. Зачем тратить драгоценные миллинаносекунды, если можно воспользоваться compile-time полиморфизмом, а конкретно паттерном CRTP? Вот сильно упрощенная и обрезанная версия того, как это может выглядеть: template <typename Derived>
class ClientBase {
protected: int sock_ = -1; sockaddr_in serv_addr_{}; std::string server_ip_; uint16_t port_; Derived& derived() { return static_cast<Derived&>(this); } public: void send_message(const std::string& message) { ssize_t bytes_sent = derived().send_impl(message); if (bytes_sent < 0) { throw std::runtime_error("Send failed"); } }
}; class TcpClient : public ClientBase<TcpClient> {
public: static constexpr int PROTOCOL_TYPE = SOCK_STREAM; ssize_t send_impl(const std::string& message) { return send(sock_, message.c_str(), message.length(), 0); } }; class UdpClient : public ClientBase<UdpClient> {
public: static constexpr int PROTOCOL_TYPE = SOCK_DGRAM; ssize_t send_impl(const std::string& message) { return sendto(sock_, message.c_str(), message.length(), 0, reinterpret_cast<sockaddr>(&serv_addr_), sizeof(serv_addr_)); }
}; И меня всегда напрягало, что в любой статье вот эти *_impl методы находятся в публичном интерфейсе наследников. Зачем они там - непонятно и это по сути детали реализации. Надо бы их скрыть. Но как? База CRTP должна иметь доступ к этим методам. Вот тут-то мы и используем трюк. Сделаем все члены наследников приватными и дадим базе CRTP доступ к кишкам наследников через friend: template <typename Derived>
class ClientBase { // ...
}; class TcpClient : public ClientBase<TcpClient> {
private: // ... friend class ClientBase<TcpClient>;
}; class UdpClient : public ClientBase<UdpClient> {
private: // ... friend class ClientBase<UdpClient>;
}; И все. Теперь все члены приватные, ClientBase имеет ко всем из них доступ и публичный интерфейс задает только ClientBase, ничего лишнего нет. Не так много народу знает об этой технике, поэтому решил о ней отдельно рассказать. Hide your secrets. Stay cool. #template