PIMPL разъяснение идиомы

При попытке удалить все детали реализации из заголовочного файла я решил использовать и опробовать идиому PIMPL. В большинстве, если не во всех примерах, например, cppreference, я видел уровни косвенного обращения, причину которых я не могу понять, кроме инкапсуляции. Примеры всегда идут с этим образцом вкуса.

типичный

//A.hpp
class A
{
public:
    A(int);
    //More non-static class methods
    void set(int);

private:
    struct a_impl;
    std::unique_ptr<struct a_impl> pimpl;
};

//A.cpp
struct A::a_impl
{
private:
    int i;
public:
    a_impl(int i) : i{i}{}
    //More non-static implementation class methods
    void set(int i) {this->i = i;}
};
A::A(int i) : std::make_unique<struct a_impl>(i) {}
A::set(int i) {pimpl->set(i);}  //????
A:://More indirect calls to non-static member functions through pointer

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

Почему бы и нет?

    //A.hpp
class A
{
public:
    A(int);
    //.....
    void set(int);

private:
    struct a_impl;
    std::unique_ptr<struct a_impl> pimpl;
};

//A.cpp
struct A::a_impl
{
    int i;
}

A::A(int i) : std::make_unique<struct a_impl>() { pimpl->i = i; }
A::set(int i) { pimpl->i = i; } //!!!!

Что я хотел бы уточнить:

1-Все ли эти образцы представлены таким образом только для образования и для хорошей практики инкапсуляции?

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

3-Или то, что я выбрал в качестве альтернативы, не идиома PIMPL?

1 ответ

Ваш собственный подход и тот, с которым вы сравниваете его, - это всего лишь два разных варианта идиомы. Херб Саттер перечислил их и многое другое в GotW # 100:

Какие части класса должны входить в объект impl? Некоторые потенциальные варианты включают в себя:

  • поместить все личные данные (но не функции) в impl;
  • положить всех частных членов в Impl;
  • поместить всех частных и защищенных членов в impl;
  • поместите всех частных не виртуальных членов в impl;
  • поместите все в impl и запишите сам открытый класс как только открытый интерфейс, каждый из которых реализован как простая функция пересылки (вариант handle/body).

У каждого есть свои сильные и слабые стороны. Для случая, который вы изучаете, ваш подход кажется лучше. В других случаях более подходящим может быть прыщ с поведением, а не просто с состоянием. На самом деле не один размер подходит всем.

Другие вопросы по тегам