0Pricing
C++ Academy · Урок

Сокрытие реализации с помощью PIMPL

Скрывайте детали реализации за идиомой указателя на реализацию.

«Сокрытие реализации с помощью PIMPL» — бесплатный урок C++ Academy на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения C++ Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс C++ Academy содержит 4 уроков всего.

Идиома PIMPL

PIMPL — «указатель на реализацию». Переместите закрытые данные класса в отдельную структуру Impl, доступ к которой осуществляется через указатель.

Зачем нужен PIMPL

Преимущества:

  • Скрывает детали реализации от заголовков
  • Уменьшает зависимости во время компиляции
  • Сохраняет стабильность ABI при добавлении закрытых членов
  • Позволяет заменять реализации

Базовая структура

Общедоступный класс содержит указатель на структуру Impl, определённую только в файле .cpp.

// widget.h
class Widget {
public:
    Widget();
    ~Widget();
    void doSomething();
private:
    struct Impl;
    std::unique_ptr<Impl> pimpl_;
};

Impl в .cpp

Структура Impl содержит все фактические данные.

// widget.cpp
struct Widget::Impl {
    std::string name;
    int counter;
    // ... anything else, freely
};

Widget::Widget()
    : pimpl_(std::make_unique<Impl>()) {}

Widget::~Widget() = default;  // must be in .cpp where Impl is complete

void Widget::doSomething() {
    pimpl_->counter++;
}

Деструктор в cpp

Деструктор необходимо определить в файле .cpp, где Impl является полным типом. Иначе unique_ptr не сможет удалить неполный тип.

Специальные функции-члены

При необходимости также следует явно объявить копирование, перемещение и присваивание. Версии, сгенерированные компилятором, не могут работать с неполным типом в заголовке.

// widget.h
class Widget {
public:
    Widget(const Widget& other);
    Widget& operator=(const Widget& other);
    Widget(Widget&&) noexcept;
    Widget& operator=(Widget&&) noexcept;
    ~Widget();
};

Накладные расходы

PIMPL добавляет косвенное обращение при каждом доступе к члену и выделение памяти в куче. Для часто вызываемых методов это может иметь значение — обязательно измерьте производительность.

Ускорение сборки

Заголовки, которые раньше подключали типы стандартной библиотеки или ресурсоёмкие зависимости, теперь могут быть компактными. Изменяйте .cpp без перекомпиляции кода потребителей.

PIMPL и наследование

Его можно сочетать с наследованием, но это усложняет конструкцию. Общедоступный класс обычно ни от чего не наследуется; Impl может свободно использовать наследование.

Варианты

Альтернативы и усовершенствования:

  • Быстрый PIMPL — встроенное хранение с использованием размещающего оператора new
  • Стабильный адрес — Impl остаётся выделенным на всё время жизни объекта
  • Стирание типа — Impl может быть полиморфным

Использование в реальных проектах

PIMPL широко используется в:

  • Qt (каждый виджет использует PIMPL)
  • Многих проприетарных библиотеках
  • Boost (в некоторых местах)

Когда использовать

Используйте PIMPL, если:

  • Вам нужна стабильность ABI между версиями
  • Ваши заголовки транзитивно подключают слишком много зависимостей
  • Вы предоставляете общедоступный API библиотеки

Когда не использовать

Не используйте PIMPL, если:

  • Класс является внутренним — его заголовок не является зависимостью потребителей
  • Накладные расходы на производительность важнее времени сборки
  • Класс небольшой или изменяется редко

Быстрая проверка

Почему деструктор класса с PIMPL необходимо определить в файле .cpp?

Итоги

PIMPL скрывает реализацию, перемещая закрытые данные в структуру Impl, доступ к которой осуществляется через unique_ptr. Это повышает стабильность ABI и ускоряет сборку, но добавляет косвенное обращение. Определяйте специальные функции-члены в .cpp, где Impl является полным типом.

Часто задаваемые вопросы

Урок «Сокрытие реализации с помощью PIMPL» бесплатный?

Да — полный текст урока «Сокрытие реализации с помощью PIMPL» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс C++ Academy, подпишись на CoddyKit PRO. Курс C++ Academy содержит 4 уроков всего.

Чему я научусь в уроке «Сокрытие реализации с помощью PIMPL»?

Скрывайте детали реализации за идиомой указателя на реализацию. Ты практикуешь C++ Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать C++ Academy?

Предыдущий опыт не требуется. C++ Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.

Сколько времени занимает урок «Сокрытие реализации с помощью PIMPL»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке C++ Academy?

Да. Каждый урок C++ Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Библиотеки только из заголовков и скомпилированные библиотеки
  2. Версионирование API и стабильность ABI
  3. Сокрытие реализации с помощью PIMPL
  4. Создание современной библиотеки утилит только из заголовков
← Назад к C++ Academy