pimpl 设计模式会阻止您编译吗?

Does pimpl design pattern prevent you from compilation?

根据这个 article,它试图解释 pimpl 解决的问题,但我发现他展示的示例没有问题。

它说: "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()
{
   /* ... */
}

但是,我看到如果Engine被修改,Fridge应该相应修改。由于 Fridge 会修改,因此使用 FridgeClient 也会被修改。
换句话说,如果 Engine 被修改,那么 Fridge 应该被重新编译,据此, Client 也将被重新编译。在这种情况下,Client 被修改是因为 Fridge 被修改了,而不是因为 Engine 被修改了。
因此,在这种情况下不存在间接问题。

我说的对吗?如果是,那么 pimpl 解决的实际问题是什么?如果不是,你能给我一个间接的例子来解释这个问题吗?

In other words, If Engine get modified, then Fridge should be recompiled.

这是正确的,但更准确地说:依赖Engine的函数需要重新编译。

and according to that, Client also will be recompiled.

没有。仅仅因为实现 Fridges 成员函数的翻译单元被重新编译,并不意味着 Fridges 客户端需要重新编译。只有修改了Fridge.h,才需要重新编译包含header的翻译单元。

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.

这就是显示的实现存在的问题。如果 Engine 是使用 PIMPL 隐藏的,那么对 Engine 的修改并不意味着对 Fridge class 的修改。它仅意味着修改 Fridge 的成员函数的实现,这些实现依赖于 Engine 并且这些实现被 PIMPL 隐藏。

如果您查看 Fridge.h 的 PIMPL 版本,您会注意到它不直接使用 Engine class,因此不包含 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-use Engine class,因此不存在违反 ODR 的可能性。