PIMPL 习语 VS 前向声明
PIMPL idiom VS forward declaration
我已经阅读了一些关于 PIMPL 习语的内容并且想知道 - 转发声明依赖类型有什么不同吗?
如果是:
- 我什么时候更喜欢使用它而不是前向声明?
- 这两个版本的编译时间是否不同?
- 其中一个比另一个更具可扩展性吗?
具体考虑依赖于Bar
的class Foo
(应该有一个Bar
类型的成员)。
Foo.h
前向声明:
class Bar;
class Foo
{
public:
Foo();
private:
Bar* _bar;
};
Foo.h
与 PIMPL:
class Foo
{
public:
Foo();
private:
/* FooImpl is an incomplete type at this point.
* Implemented in cpp file and has a member of type Bar.
*/
class FooImpl;
FooImpl* _fooImpl;
}
请忽略原始指针的用法 - 我只是想说明一点。
PIMPL 模式通常用于完全隐藏使用您的代码的实现细节 class。
例如,您的 class 可能包装了 platform-specific 功能。即使您使用前向声明 and/or 条件编译,您最终也会在 header 文件中公开 platform-specific 代码。这意味着任何使用你的 class 的代码在这些类型上也会以 header-dependency 结束,这意味着你的 class 可能会根据平台而改变(例如,大小可能是不同)。
PIMPL 模式可以让您将所有 platform-specific 细节隐藏在实现文件(通常是 *.cpp 或类似文件)中。这意味着程序中其他任何地方的其他代码都无法直接看到它,从而使您的包装器 class 在所有平台上保持干净和一致。
这只是 PIMPL 派上用场的例子之一,但它还有其他用途。
同样值得注意的是,并不是所有的东西都可以forward-declared,并且前向声明通常需要做出不受欢迎的让步,例如到处使用指针或引用。
I have read a bit about the PIMPL idiom and was wondering - is it any different to forward declaring the dependent type(s)?
是的,它们是不同的。 PIMPL idiom (it has several names) 专门用于隐藏客户端代码的实现细节。这样做的原因有很多,包括(但不限于);
- 当 class 细节改变时隔离重建(它们是隐藏的)
- 最小化必需的或冲突的 header 包含物
- 总体构建时间减少
- 最低导出要求(尽管抽象 classes 也可用于此目的)
- 更容易控制因多个目标或平台而异的实施细节
本质上,PIMPL 提供了一种 "hide" 从客户端代码实现的技术 - 无论何时都需要。
When will I prefer using [PIMPL] over forward declaration?
这真的与意图有关 - 您的代码与抽象有关 - 照顾好这些抽象,滋养它们并保护它们,它们将为您提供良好的服务。
问题变成了 - 哪一个更能代表您的意图?我敢说 FooImpl
更好,我感觉到您的意图是向客户端隐藏 class 的实现,并且此实现更好地代表了该意图(因为 FooImpl
不是客户端可访问)。
如果您的意图是在代码的其他地方使用 Bar
,在 class Foo
之外,那么该实现更好,因为这是意图并且该实现允许你这样做。
Do these two versions differ in their compilation time?
我对此表示怀疑。 Bar
和 FooImpl
的实现在它们定义的翻译单元之外是不可见的。
Is one of them more scalable than the other?
不是,不是。从某种一般意义上讲,代码越清晰,人们就越容易扩展它。
我已经阅读了一些关于 PIMPL 习语的内容并且想知道 - 转发声明依赖类型有什么不同吗?
如果是:
- 我什么时候更喜欢使用它而不是前向声明?
- 这两个版本的编译时间是否不同?
- 其中一个比另一个更具可扩展性吗?
具体考虑依赖于Bar
的class Foo
(应该有一个Bar
类型的成员)。
Foo.h
前向声明:
class Bar;
class Foo
{
public:
Foo();
private:
Bar* _bar;
};
Foo.h
与 PIMPL:
class Foo
{
public:
Foo();
private:
/* FooImpl is an incomplete type at this point.
* Implemented in cpp file and has a member of type Bar.
*/
class FooImpl;
FooImpl* _fooImpl;
}
请忽略原始指针的用法 - 我只是想说明一点。
PIMPL 模式通常用于完全隐藏使用您的代码的实现细节 class。
例如,您的 class 可能包装了 platform-specific 功能。即使您使用前向声明 and/or 条件编译,您最终也会在 header 文件中公开 platform-specific 代码。这意味着任何使用你的 class 的代码在这些类型上也会以 header-dependency 结束,这意味着你的 class 可能会根据平台而改变(例如,大小可能是不同)。
PIMPL 模式可以让您将所有 platform-specific 细节隐藏在实现文件(通常是 *.cpp 或类似文件)中。这意味着程序中其他任何地方的其他代码都无法直接看到它,从而使您的包装器 class 在所有平台上保持干净和一致。
这只是 PIMPL 派上用场的例子之一,但它还有其他用途。
同样值得注意的是,并不是所有的东西都可以forward-declared,并且前向声明通常需要做出不受欢迎的让步,例如到处使用指针或引用。
I have read a bit about the PIMPL idiom and was wondering - is it any different to forward declaring the dependent type(s)?
是的,它们是不同的。 PIMPL idiom (it has several names) 专门用于隐藏客户端代码的实现细节。这样做的原因有很多,包括(但不限于);
- 当 class 细节改变时隔离重建(它们是隐藏的)
- 最小化必需的或冲突的 header 包含物
- 总体构建时间减少
- 最低导出要求(尽管抽象 classes 也可用于此目的)
- 更容易控制因多个目标或平台而异的实施细节
本质上,PIMPL 提供了一种 "hide" 从客户端代码实现的技术 - 无论何时都需要。
When will I prefer using [PIMPL] over forward declaration?
这真的与意图有关 - 您的代码与抽象有关 - 照顾好这些抽象,滋养它们并保护它们,它们将为您提供良好的服务。
问题变成了 - 哪一个更能代表您的意图?我敢说 FooImpl
更好,我感觉到您的意图是向客户端隐藏 class 的实现,并且此实现更好地代表了该意图(因为 FooImpl
不是客户端可访问)。
如果您的意图是在代码的其他地方使用 Bar
,在 class Foo
之外,那么该实现更好,因为这是意图并且该实现允许你这样做。
Do these two versions differ in their compilation time?
我对此表示怀疑。 Bar
和 FooImpl
的实现在它们定义的翻译单元之外是不可见的。
Is one of them more scalable than the other?
不是,不是。从某种一般意义上讲,代码越清晰,人们就越容易扩展它。