According to this article, it's trying to explain the problem which pimpl
solve but i see that there is no problem in example he showed.
It says that: "there is an issue with below design (that could be serious or not, depending on how many clients Fridge has). Since Fridge.h #includes Engine.h, any client of the Fridge class will indirectly #include the Engine class. So when the Engine class is modified, all the clients of Fridge have to recompile, even if they don’t use Engine directly."
#include "Engine.h"
class Fridge
{
public:
void coolDown();
private:
Engine engine_;
};
#include "Fridge.h"
void Fridge::coolDown()
{
/* ... */
}
But, i see that if Engine
is modified, Fridge
should modify according. And since Fridge
will modify, the Client
which uses Fridge
will also get modified.
In other words, If Engine
get modified, then Fridge
should be recompiled and according to that, Client
also will be recompiled. In this case Client
modified because Fridge
is modified NOT because Engine
is modified.
So, there is no indirection problem in this situation.
Am i right? if yes, So, what's the actual problem does pimpl
solve? if no, can you give me an indirection example which explain this problem?
In other words, If
Engine
get modified, thenFridge
should be recompiled.
This is correct, but to be more accurate: The functions that depend on Engine
need to be recompiled.
and according to that, Client also will be recompiled.
No. Just because translation unit that implements Fridges member functions is recompiled, doesn't mean that Fridges clients would need to be recompiled. Only if Fridge.h is modified, do translation units including that header need to be recompiled.
But, i see that if
Engine
is modified,Fridge
should modify according. And sinceFridge
will modify, theClient
which usesFridge
will also get modified.
That is the problem that the shown implementation has. If Engine
was instead hidden using PIMPL, then a modification to Engine
wouldn't imply a modification to the Fridge
class. It only implies modification to the implementation of member functions of Fridge
, which depend on Engine
and those implementations are hidden by the PIMPL.
If you take a look at the PIMPL version of Fridge.h
, you'll notice that it doesn't use Engine
class directly, and consequently doesn't include Engine.h
. A change to Engine.h
therefore doesn't cause changes in Fridge.h
and therefore doesn't cause changes in translation units that include 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?
If one translation unit uses a different definition of Engine
than another translation unit, then the program violates the one definition rule, and the behaviour will be undefined.
With PIMPL, translation units that include Fridge.h
do not ODR-use Engine
class at all, so there is no possibility of ODR violation.