pimpl设计模式会妨碍您编译吗?

时间:2019-05-31 15:36:36

标签: c++ pimpl-idiom

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

它说: “以下设计存在问题(取决于Fridge拥有多少个客户端,这个问题是否严重。由于Fridge.h #includes Engine.h,所以Fridge类的任何客户端都将间接#includeEngine类。因此修改Engine类后,即使没有直接使用Engine,Fridge的所有客户端也必须重新编译。”

#include "Engine.h"

class Fridge
{
public:
   void coolDown();
private:
   Engine engine_;
};
#include "Fridge.h"

void Fridge::coolDown()
{
   /* ... */
}

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

我是对的吗?如果是,那么Engine解决的实际问题是什么?如果没有,您能给我一个间接例子来解释这个问题吗?

1 个答案:

答案 0 :(得分:3)

  

换句话说,如果Engine被修改,那么Fridge应该被重新编译。

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

  

并且据此,还将重新编译Client。

不。仅仅因为重新编译了实现Fridges成员功能的翻译单元,并不意味着就需要重新编译Fridges客户。仅当Fridge.h修改后,才需要重新编译包括该标头的翻译单元。

  

但是,我看到如果Engine被修改,Fridge应该被修改。而且由于Fridge将被修改,所以使用Client的{​​{1}}也将被修改。

这是所示实现所存在的问题。如果改为使用PIMPL隐藏Fridge,则对Engine的修改并不意味着对Engine类的修改。它仅意味着对Fridge成员函数的实现进行修改,该函数依赖于Fridge,而这些实现被PIMPL隐藏。

如果您查看Engine的PIMPL版本,您会发现它不直接使用Fridge.h类,因此不包含Engine。因此,Engine.h的更改不会引起Engine.h的更改,因此不会引起包含Fridge.h的翻译单元的更改:

Fridge.h

  

您能举个例子,修改Engine.h后不重新编译客户端翻译单元会导致问题吗?

如果一个翻译单元使用的class Fridge { public: Fridge(); ~Fridge(); void coolDown(); private: class FridgeImpl; FridgeImpl* impl_; }; 定义与另一个翻译单元不同,则程序违反了一个定义规则,并且行为将是未定义的。

使用PIMPL时,包含Engine的翻译单元完全不使用ODR使用Fridge.h类,因此不存在违反ODR的可能性。