Можно ли обернуть наддува с помощью Pimpl
-
06-07-2019 - |
Вопрос
в проекте мы хотим обернуть сокет Boost Asio таким образом, чтобы класс using или оболочка .h не обязательно включали заголовки boost.
Мы обычно используем указатели и предварительные объявления для упакованных классов.
Декларация Фоварда:
namespace boost
{
namespace asio
{
namespace ip
{
class udp;
}
}
}
А затем объявить сокет:
scoped_ptr<boost::asio::ip::udp::socket> socket_;
scoped_ptr<boost::asio::ip::udp::endpoint> receiveEp_;
(Если вы не знаете scoped_ptr, игнорируйте его, проблема равна стандартному * указателю.)
Но это дает ошибку компилятора:
error C2027: use of undefined type 'boost::asio::ip::udp'
Я понимаю, что это потому, что udp на самом деле не пространство имен, а сам класс. Мы хотим использовать только внутренний класс, есть идеи?
Решение
С внутренними типами ваш единственный вариант - обернуть все. Спрячьте указатели с областью видимости внутри заранее объявленного класса. Пользователи увидят только ваш API и передадут ваши собственные объекты вместо объектов повышения.
В вашем примере, хотя scoped_ptr похожи на объявления закрытых членов, вы можете обойтись простым:
// header
class SomeClass
{
public:
SomeClass();
// stuff
private:
scoped_ptr<class pimpl_bla> _m;
};
// source
class pimpl_bla
{
public:
scoped_ptr<boost::asio::ip::udp::socket> socket_;
};
SomeClass::SomeClass()
:_m(new pimpl_bla)
{
}
Другие советы
Если вы используете pimpl, почему вы помещаете переменные-члены в заголовок? Используются ли в вашем интерфейсе определения типа сокета и конечной точки? Если они не являются частью вашего интерфейса, весь смысл идиомы pimpl в том, что вы не определяете переменные-члены класса в заголовочном файле; это детали реализации.
Я ожидаю что-то подобное в заголовочном файле:
// ...
class MyClass {
public:
MyClass();
// .. Other member functions
private:
struct Imp;
boost::shared_ptr<Imp> m_imp; // This is the only member variable.
};
А затем в вашем файле реализации:
#include <boost/asio/whatever.hpp>
struct MyClass::Imp
{
scoped_ptr<boost::asio::ip::udp::socket> socket_;
scoped_ptr<boost::asio::ip::udp::endpoint> receiveEp_;
// Remainder of implementation class ...
};
// Other implementation details.
Чтобы ответить на ваш конкретный вопрос, типами, которые вы пытаетесь использовать, являются typedefs в классе asio udp, поэтому компилятор должен видеть определение этого класса, чтобы использовать его.