-1

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?

Islam Abdeen
  • 451
  • 2
  • 7
  • The pimpl design pattern, properly implemented (which this code clearly makes no attempt at doing), solves the problem of any *consumer* of `Fridge.h` from being recompiled on change to `Engine.h`. A proper pimpl would not include `Engine.h` in `Fridge.h`, and therefore changes to `Engine.h` would not affect consumers of `Fridge.h` except *one* : `Fridge.cpp`. – WhozCraig May 31 '19 at 15:44

1 Answers1

3

In other words, If Engine get modified, then Fridge 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 since Fridge will modify, the Client which uses Fridge 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.

eerorika
  • 181,943
  • 10
  • 144
  • 256
  • Can you give me example how NOT recompiling `Client` translation unit after modifying `Engine.h` will cause issue? I think if we don't recompile `Client` after modifying `Engine.h` will not give us any undesired behavior. – Islam Abdeen Jun 01 '19 at 00:31