Г
Грокаем C++
@grokaemcpp9.3K подп.
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
3.8K
просмотров
2412
символов
Нет
эмодзи
Нет
медиа

Другие посты @grokaemcpp

Все посты канала →
​​CRTP + friend #опытным Допустим, вам нужно написать tcp и — @grokaemcpp | PostSniper