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
会修改,因此使用 Fridge
的 Client
也会被修改。
换句话说,如果 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 的可能性。
根据这个 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
会修改,因此使用 Fridge
的 Client
也会被修改。
换句话说,如果 Engine
被修改,那么 Fridge
应该被重新编译,据此, Client
也将被重新编译。在这种情况下,Client
被修改是因为 Fridge
被修改了,而不是因为 Engine
被修改了。
因此,在这种情况下不存在间接问题。
我说的对吗?如果是,那么 pimpl
解决的实际问题是什么?如果不是,你能给我一个间接的例子来解释这个问题吗?
In other words, If
Engine
get modified, thenFridge
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 sinceFridge
will modify, theClient
which usesFridge
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 的可能性。