pimpl 类的私人成员?

发布于 2024-08-20 01:24:22 字数 118 浏览 8 评论 0原文

pimpl 习惯用法中使用的实现类是否有任何理由拥有任何私有成员?我真正能想到的唯一原因是保护自己免受自己的伤害——即私有成员用于强制执行类和用户之间的某种契约,在这种情况下,类和用户是相当密切相关的,所以它似乎没有必要。

Is there any reason for the implementation class as used in the pimpl idiom to have any private members at all? The only reason I can really think of is to protect yourself from yourself -- i.e. the private members serve to enforce some kind of contract between the class and the user, and in this case the class and the user are rather intimately related, so it seems unnecessary.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

能否归途做我良人 2024-08-27 01:24:22

我认为人们将 Pimpl 惯用语与适配器/桥/策略模式混淆了。习语是特定于某种语言的。模式可以应用于多种语言。

Pimpl 习惯用法旨在解决 C++ 中的以下问题:类的私有成员在类声明中可见,这会向类的用户添加不必要的 #include 依赖项。这个习惯用法也称为编译器防火墙

如果实现是直接编写在外部类相应的 *.cpp 文件中,并且无法在模块外部访问,那么我认为简单地使用 Pimpl 类的结构就可以了。为了进一步强化实现并不意味着直接重用的想法,我将它们定义为私有内部结构:

// foo.h
class Foo : boost::noncopyable
{
public:
   ...

private:
   struct Impl;
   boost::scoped_ptr<Impl> impl_;
};

// foo.cpp
struct Foo::Impl
{
   // Impl method and member definitions
};

// Foo method definitions

一旦实现类有了头文件,我认为我们不再谈论 Pimpl成语。我们更多地谈论适配器、桥、策略、接口类等等……

只是我的 2 美分。

I think people are confusing the Pimpl idiom with Adapter/Bridge/Strategy patterns. Idioms are specific to a language. Patterns can apply to many languages.

The Pimpl idiom was devised to address the following problem in C++: Private members of a class are visible in the class declaration, which adds unnecessary #include dependencies to the user of the class. This idiom is also known as compiler firewall.

If the implementation is written directly in the outer class's corresponding *.cpp file, and is not accessible outside the module, then I think its perfectly fine to simply use a struct for the Pimpl class. To further re-enforce the idea that implementations are not meant to be directly re-used, I define them as a private inner struct:

// foo.h
class Foo : boost::noncopyable
{
public:
   ...

private:
   struct Impl;
   boost::scoped_ptr<Impl> impl_;
};

// foo.cpp
struct Foo::Impl
{
   // Impl method and member definitions
};

// Foo method definitions

As soon as there's a header file for the implementation class, I think we are no longer talking about the Pimpl idiom. We are rather talking about Adapter, Bridge, Strategy, interface classes, etc...

Just my 2 cents.

花伊自在美 2024-08-27 01:24:22

取决于您的 pImpl 实现 - 特别是您强制执行类不变式的地方,但一般来说,我认为 impl 部分不需要具有受保护/私有成员。事实上,我通常将其声明为一个结构体。

Depends on your implementation of pImpl - specifically where you enforce the class invariant, but in general I see no need for the impl part to have protected/private members. In fact, I usually declare it as a struct.

浅浅 2024-08-27 01:24:22

理论上,pimpl 类仍然只是一个像其他类一样的类。它是接口的具体实现并不意味着其他代码不是 pimpl 类本身的客户端。

也就是说,在实践中我发现 pimpl 类往往更接近于具有某些成员函数的结构,而不是成熟的对象,并且不太需要将接口与实现分开。

In theory a pimpl class is still just a class like any other. That it is a concrete implementation of an interface doesn't mean that other code isn't a client of the pimpl class itself.

That said, in practice I have found that pimpl classes tend to be much closer to structs with some member functions rather than full fledged objects, and have less need to separate the interface from the implementation.

醉梦枕江山 2024-08-27 01:24:22

为什么它不应该有私人成员?仅仅因为您将一个接口定义为 PIMPL 并不意味着您在其他任何时候都不想使用该类。

依然是一个班级。数据可能应该是私有的或受保护的。对公共、私人或受保护永远无法访问的数据进行操作。您可能希望公开、受保护或公开的操作。

Why shouldn't it have private members? Just because you're defining one interface as PIMPL doesn't mean that you will at no other time want to use the class.

It's still a class. Data should probably be private or protected. Operations on data that will never be accessible to the public, private or protected. Operations that you might wish to expose, protected, or public.

伤感在游骋 2024-08-27 01:24:22

我能真正想到的唯一原因
就是保护自己免受自己伤害

这就是为什么“私有”和“受保护”首先存在的原因。当然,您应该在实现中使用它们 - 唯一我不会的情况是如果实现没有行为(在这种情况下它不是真正的实现)。

The only reason I can really think of
is to protect yourself from yourself

Which is why "private" and "protected" are there in the first place. Of course you should use them in your implementation - the only time I would not is if the implementation has no behaviour (in which case it isn't really an implementation).

半仙 2024-08-27 01:24:22

(我误解了这个问题,所以我改变了我的答案。)

由带有 pimpl 的类所指向的实现类应该是一个常规类,与其他类一样有足够的理由隐藏私有详细信息。事实上,它通常是一个预先存在的类,稍后添加 pimpl 层以打破依赖关系,并可能稍微简化接口。

(I misunderstood the question, so I'm changing my answer.)

The implementing class, which is pointed to by the class with the pimpl, should be a regular class, with just as much reason to hide private details as any other. In fact, it's often a pre-existing class, with the pimpl layer added later to break dependencies and perhaps simplify the interface a bit.

年华零落成诗 2024-08-27 01:24:22

因为private意味着更好的数据封装。

我知道,这看起来很愚蠢,但我们有一种在工作中定义接口的方法,非常简单:

class Interface;

class Concrete { public: .... private: Interface* m_interface; }

class ConcreteFoo: public Interface {};

主要优点:您可以随时更换另一个 ConcreteBar。事实上,它是 PimplStrategy 模式的组合,而 Concrete 的构造函数将调用 Factory > 将负责服务有效的对象。

如果你想不出第二种实现心脏的方法,就把它封装在一个类中。这样,如果您以后需要重构,您只需使用完全相同的方法集组合一个抽象接口,更改一些指针(和构造函数)就可以了;)

Because private means better data encapsulation.

It seems silly, I know, but we have a way of defining interfaces at work that is very simple:

class Interface;

class Concrete { public: .... private: Interface* m_interface; }

class ConcreteFoo: public Interface {};

The main advantage: you can swap for another ConcreteBar at any moment. It is, in fact, a combination of Pimpl and Strategy pattern, and the constructor of Concrete will call a Factory that will be responsible to serve the effective object.

If you cannot think of a second way of implementing the heart, just encapsulate it in a class. This way if you later have to refactor, you'll just have to compose an abstract Interface with the exact same set of methods, change a few pointers (and the constructor) and you'll be all right ;)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文