Согласно этому статья, он пытается объяснить проблему, которую pimpl решает, но я вижу, что в примере, который он показал, нет проблемы.
В нем говорится, что: «Существует проблема с приведенным ниже дизайном (которая может быть серьезной или нет, в зависимости от того, сколько клиентов у Fridge). Поскольку Fridge.h #includes Engine.h, любой клиент класса Fridge будет косвенно включать класс Engine. когда класс Engine изменяется, все клиенты Fridge должны перекомпилировать, даже если они не используют Engine напрямую».
#include "Engine.h"
class Fridge
{
public:
void coolDown();
private:
Engine engine_;
};
#include "Fridge.h"
void Fridge::coolDown()
{
/* ... */
}
Но я вижу, что если Engine изменено, Fridge должно измениться соответственно. И поскольку Fridge будет изменяться, Client, использующий Fridge, также будет изменен.
Другими словами, если Engine модифицируется, то Fridge следует перекомпилировать и, соответственно, Client также будет перекомпилирован. В этом случае Client изменено, потому что Fridge изменено НЕ потому, что Engine изменено.
Таким образом, в этой ситуации нет проблемы косвенности.
Я прав? если да, то какую проблему решает pimpl? если нет, можете ли вы привести пример косвенности, объясняющий эту проблему?





In other words, If
Engineget modified, thenFridgeshould be recompiled.
Это правильно, но если быть более точным: функции, зависящие от Engine, необходимо перекомпилировать.
and according to that, Client also will be recompiled.
Нет. Тот факт, что модуль трансляции, реализующий функции-члены Fridges, перекомпилируется, не означает, что клиенты Fridges должны быть перекомпилированы. Только в случае изменения Fridge.h единицы перевода, включая этот заголовок, необходимо перекомпилировать.
But, i see that if
Engineis modified,Fridgeshould modify according. And sinceFridgewill modify, theClientwhich usesFridgewill also get modified.
Это проблема показанной реализации. Если бы вместо этого Engine был скрыт с помощью PIMPL, то изменение Engine не подразумевало бы изменение класса Fridge. Это подразумевает только изменение реализации функций-членов Fridge, которые зависят от Engine, и эти реализации скрыты PIMPL.
Если вы посмотрите на версию PIMPL Fridge.h, вы заметите, что она не использует класс Engine напрямую и, следовательно, не включает Engine.h. Таким образом, изменение Engine.h не вызывает изменений в Fridge.h и, следовательно, не вызывает изменений в единицах перевода, которые включают Fridge.h:
class Fridge { public: Fridge(); ~Fridge(); void coolDown(); private: class FridgeImpl; FridgeImpl* impl_; };
Can you give me example how NOT recompiling Client translation unit after modifying Engine.h will cause issue?
Если одна единица перевода использует другое определение Engine, чем другая единица перевода, то программа нарушает одно правило определения, и поведение будет неопределенным.
С PIMPL единицы перевода, которые включают Fridge.h, вообще не используют ODR-класс Engine, поэтому вероятность нарушения ODR отсутствует.
Можете ли вы привести пример того, как НЕ перекомпилировать единицу перевода Client после изменения Engine.h вызовет проблему? Я думаю, что если мы не перекомпилируем Client после изменения Engine.h, это не приведет к нежелательному поведению.
Шаблон проектирования pimpl, правильно реализованный (который этот код явно не пытается сделать), решает проблему перекомпиляции любого потребитель для
Fridge.hпри изменении наEngine.h. Правильный pimpl не будет включатьEngine.hвFridge.h, поэтому изменения вEngine.hне повлияют на потребителейFridge.h, за исключением один :Fridge.cpp.