Частные члены в классе pimpl? - PullRequest
       15

Частные члены в классе pimpl?

5 голосов
/ 01 февраля 2010

Есть ли какая-либо причина, по которой класс реализации, используемый в идиоме pimpl, вообще имеет каких-либо закрытых членов? Единственная причина, по которой я могу придумать, - это защитить себя от себя - то есть частные члены служат для принудительного выполнения какого-то договора между классом и пользователем, и в этом случае класс и пользователь довольно тесно связаны, кажется ненужным.

Ответы [ 7 ]

11 голосов
/ 01 февраля 2010

Я думаю, что люди путают идиому Pimpl с Адаптером / Мостом / Стратегией паттернами . Идиомы специфичны для языка. Шаблоны могут применяться ко многим языкам.

Идиома Pimpl была разработана для решения следующей проблемы в C ++: закрытые члены класса видны в объявлении класса, что добавляет ненужные зависимости #include для пользователя класса. Эта идиома также известна как межсетевой экран компилятора .

Если реализация написана непосредственно в соответствующем файле * .cpp внешнего класса и недоступна за пределами модуля, то Я думаю, что это прекрасно, просто использовать структуру для класса Pimpl . Для дальнейшего закрепления идеи о том, что реализации не предназначены для повторного использования напрямую, я определил их как частную внутреннюю структуру:

// foo.h
class Foo : boost::noncopyable
{
public:
   ...

private:
   struct Impl;
   boost::scoped_ptr<Impl> impl_;
};

// foo.cpp
struct Foo::Impl
{
   // Impl method and member definitions
};

// Foo method definitions

Как только появится заголовочный файл для класса реализации, я думаю, что мы больше не говорим об идиоме Pimpl. Мы скорее говорим об адаптере, мосте, стратегии, интерфейсных классах и т.д ...

Только мои 2 цента.

6 голосов
/ 01 февраля 2010

Зависит от вашей реализации pImpl - особенно там, где вы применяете инвариант класса, но в целом я не вижу необходимости для части impl иметь защищенные / закрытые члены. На самом деле, я обычно объявляю это как структуру.

4 голосов
/ 01 февраля 2010

Теоретически, класс pimpl - это просто класс, как и любой другой. То, что это конкретная реализация интерфейса, не означает, что другой код не является клиентом самого класса pimpl.

Тем не менее, на практике я обнаружил, что классы pimpl, как правило, гораздо ближе к структурам с некоторыми функциями-членами, а не полноценными объектами, и им меньше нужно отделять интерфейс от реализации.

2 голосов
/ 01 февраля 2010

Почему у него не должно быть частных участников? Тот факт, что вы определяете один интерфейс как PIMPL, не означает, что вы никогда не захотите использовать этот класс.

Это все еще класс. Данные, вероятно, должны быть конфиденциальными или защищенными. Операции с данными, которые никогда не будут доступны общественности, частным лицам или защищены. Операции, которые вы, возможно, пожелаете раскрыть, защитить или опубликовать.

1 голос
/ 01 февраля 2010

Единственная причина, по которой я могу думать это защитить себя от себя

Именно поэтому "частные" и "защищенные" существуют в первую очередь. Конечно, вы должны использовать их в своей реализации - единственный раз, когда я бы этого не сделал, это если реализация не имеет поведения (в этом случае это не совсем реализация).

0 голосов
/ 01 февраля 2010

Потому что private означает лучшую инкапсуляцию данных.

Это кажется глупым, я знаю, но у нас есть способ определения интерфейсов на работе, который очень прост:

class Interface;

class Concrete { public: .... private: Interface* m_interface; }

class ConcreteFoo: public Interface {};

Основное преимущество: вы можете поменяться на другое ConcreteBar в любой момент. Фактически это комбинация шаблонов Pimpl и Strategy, а конструктор Concrete вызовет Factory, который будет отвечать за обслуживание эффективного объекта.

Если вы не можете придумать второй способ реализации сердца, просто заключите его в класс. Таким образом, если вам позже потребуется рефакторинг, вам просто нужно составить реферат Interface с точно таким же набором методов, изменить несколько указателей (и конструктор), и все будет в порядке;)

0 голосов
/ 01 февраля 2010

(Я неправильно понял вопрос, поэтому я меняю свой ответ.)

Реализующий класс, на который указывает класс с pimpl, должен быть обычным классом с той же самой причиной, чтобы скрыть личные детали, как и любой другой. Фактически, это часто уже существующий класс с добавленным позже слоем pimpl, чтобы сломать зависимости и, возможно, немного упростить интерфейс.

...