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).
У каждого есть свои сильные и слабые стороны. Для случая, который вы изучаете, ваш подход кажется лучше. В других случаях более подходящим может быть прыщ с поведением, а не просто с состоянием. На самом деле не один размер подходит всем.