据我所知,pimpl习语只是因为C ++强制你将所有私有类成员放在标题中而存在。如果标题只包含公共接口,理论上,类实现中的任何更改都不需要重新编译程序的其余部分。

我想知道的是为什么C ++不是为了方便而设计的。为什么它要求一个类的私有部分公开显示在标题中(没有双关语)?

有帮助吗?

解决方案

这与对象的大小有关。除其他外,h文件用于确定对象的大小。如果没有给出私有成员,那么你就不会知道一个对象有多大了。

您可以通过以下方式模拟您想要的行为:

class MyClass
{
public:
   // public stuff

private:
#include "MyClassPrivate.h"
};

这不会强制执行此行为,但会从.h文件中获取私有内容。 在不利方面,这会添加另一个要维护的文件。 此外,在visual studio中,intellisense不适用于私人成员 - 这可能是加号或减号。

其他提示

我认为这里存在混淆。问题不在于标题。标头不做任何事情(它们只是在几个源代码文件中包含公共位源文本的方法)。

问题,就像有一个问题一样,C ++中的类声明必须定义实例需要具有的所有内容,即公共和私有才能工作。 (Java也是如此,但是外部编译类的引用工作方式使得不必使用共享头之类的东西。)

有些人需要知道所使用的具体类以及如何使用其构造函数来提供实现,这就是常见的面向对象技术(不仅仅是C ++)的本质,即使你只使用了公共部分。 (3,下面)中的设备隐藏它。无论你是否(3),(1,下面)中的实践都将这些问题分开。

  1. 使用仅定义公共部分的抽象类,主要是方法,并让实现类继承该抽象类。因此,使用标头的通常约定,有一个共享的abstract.hpp。还有一个implementation.hpp声明了继承的类,它只传递给实现实现方法的模块。 implementation.hpp文件将#include" abstract.hpp"用于它所做的类声明,因此对于抽象接口的声明只有一个维护点。

  2. 现在,如果你想强制隐藏实现类声明,你需要有一些方法来请求构建一个具体的实例而不拥有特定的,完整的类声明:你不能使用new和你不能使用本地实例。 (你可以删除。)辅助函数的介绍(包括提供对类实例的引用的其他类的方法)是替代。

  3. 与用作抽象类/接口的共享定义的头文件一起或作为其一部分,包括外部帮助器函数的函数签名。这些函数应该在作为特定类实现的一部分的模块中实现(因此他们看到完整的类声明并且可以运用构造函数)。辅助函数的签名可能与构造函数的签名非常相似,但它返回一个实例引用作为结果(此构造函数代理可以返回NULL指针,如果您喜欢这种东西,它甚至可以抛出异常)。辅助函数构造一个特定的实现实例,并返回它作为对抽象类实例的引用。

  4. 任务完成。

    哦,重新编译和重新编译应该按照你想要的方式工作,避免在只有实现发生变化时重新编译调用模块(因为调用模块不再对实现进行任何存储分配)。

你们都忽视了问题的关键点 -

为什么开发人员必须输入PIMPL代码?

对我来说,我能想到的最好的答案是我们没有很好的方式来表达允许你对其进行操作的C ++代码。例如,编译时(或预处理器,或其他)反射或代码DOM。

C ++非常需要其中一个或两个可供开发人员进行元编程。

然后你可以在你的公共MyClass.h中写下这样的东西:

#pragma pimpl(MyClass_private.hpp)

然后编写自己的,非常简单的包装器生成器。

有人会比我有更冗长的答案,但快速响应是双重的:编译器需要知道结构的所有成员以确定存储空间要求,编译器需要知道顺序那些成员以确定的方式产生抵消。

语言已经相当复杂;我认为在代码中划分结构化数据定义的机制将是一个灾难。

通常,我一直看到用于定义实施行为的政策类平普尔的方式。我认为使用策略模式还有一些额外的好处 - 更容易交换实现,可以轻松地将多个部分实现组合到一个单元中,从而允许您将实现代码分解为功能,可重用的单元等。

可能是因为在通过值传递实例,在其他类中聚合它等时需要类的大小?

如果C ++不支持值语义,那就没问题,但确实如此。

是的,但是......

你需要阅读Stroustrup的“C ++的设计和演变”。书。它会抑制C ++的使用。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top