C ++ совет от Code Complete по инкапсуляции? - PullRequest
6 голосов
/ 12 июня 2011

В разделе «Надлежащая инкапсуляция» в Code Complete рекомендуется скрыть подробности частной реализации.Пример приведен в C ++.Идея состоит в том, чтобы полностью отделить интерфейс от реализации, даже на уровне класса.

class Employee {
public:
    ...
    Employee( ... );
    ...

    FullName GetName() const;
    String GetAddress() const;

private:
    EmployeeImplementation *m_implementation;
};

Это действительно хорошее использование времени?Мало того, что это кажется неэффективным (какие потери производительности это даст?), Но и весь девиз Code Complete («управление сложностью»), кажется, полностью изменен - ​​разве это не добавляет сложности?

Ответы [ 5 ]

3 голосов
/ 12 июня 2011

Еще одним преимуществом идиомы PIMPL может быть поддержание ABI .См. Практическая идиома Pimpl .

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

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

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

2 голосов
/ 12 июня 2011

Что ж, это увеличивает инкапсуляцию, поскольку ваш заголовочный файл теперь содержит только открытые члены и один указатель на приватную реализацию.

Это также (немного?) Снижает производительность из-за дополнительного уровня косвенности.

Ключевым вопросом здесь является «сокращение времени компиляции».

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

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

Если вы распространяете библиотеку, тогда история совершенно другая.Изменения в заголовках означают, что любые ваши клиенты должны будут перестроить свои приложения для использования вашей новой версии, даже если вы изменили приватные части класса.Использование здесь идиомы pimpl означало бы, что изменение невидимо для пользователей вашей динамической библиотеки.

1 голос
/ 12 июня 2011

Эта идиома используется для абстрагирования от плохих заголовков, и не более того. Используйте его только в том случае, если типы, требуемые для определения класса, включают в себя заголовки, которые пропускают макросы, занимают много времени для компиляции и т. Д. Кроме того, это обычно не считается правильным решением. Так как ваша реализация в любом случае требует динамического размещения и ссылочной семантики, вы можете просто сделать ее интерфейсом и предложить метод CreateForMyPlatform(), который имеет определение в файле cpp. По крайней мере, вы можете использовать умные указатели для этого сценария.

1 голос
/ 12 июня 2011

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

Предположим, вы предоставляете библиотеку инфраструктуры, которую используют многие другие компоненты. Затем, как указывало @zvrba, каждый раз, когда вы изменяете детали своей частной реализации, все ваши клиенты должны перекомпилировать. Это может быть не сложно, но в больших и сложных проектах интеграция компонентов может быть сложной задачей. С pimpl, если ваша библиотека динамическая (dll, .so), ваши клиенты не требуют никаких действий.

1 голос
/ 12 июня 2011

Дополнительный уровень косвенности через указатель может вызвать дополнительные пропуски в кеше и замедлить вашу программу.AFAIK, эта идиома (PIMPL) чаще всего предлагается для сокращения времени компиляции.Скажем, у вас есть заголовок employee.h со всеми полями в классе вместо одного указателя.Теперь, когда вы изменяете данные сотрудника (например, добавляете или удаляете поле), КАЖДЫЙ файл, включающий employee.h, должен быть перекомпилирован.Если все, что у вас есть, это один указатель на класс реализации, определенный в employee.cpp, то при изменении EmployeeImplementation.

необходимо перекомпилировать ТОЛЬКО employee.cpp. Теперь уменьшенное время компиляции стоит дополнительногоСтоимость?Только вы можете решить это.

...