Pimpl 习惯用法和内部对象协作,无需友元声明
我正在使用 pimpl 习惯用法实现几个类,并且遇到了一些设计问题。
首先,我总是看到 pimpl 这样做
class Object
{
public:
Visible();
~Visible();
.. etc ..
private:
class ObjectImpl *_pimpl;
};
,我有几个类使用这种方法,我的问题是其中几个类需要访问彼此的实现细节,但 _pimpl 指针被声明为私有。
任何人都可以看到将 _pimpl 公开的缺点。显然,如果它是公开的,那么有人可能会意外(或故意)重新分配它。 (我忽略了“私有”可以被定义为“公共”并授予访问权限的事实。如果你这样做,那么你应得的)。
我知道我的设计可能有缺陷,并且也欢迎任何类似的评论。
我真的很讨厌使用朋友,并且不确定他们是否会提供帮助,因为您无法在没有完全定义 Object 的情况下转发声明 Object::ObjectImpl 。
即
...
private:
class ObjectImpl *_pimpl;
friend class OtherObject::OtherObjectImpl; // this needs a fully qualified OtherObject
};
谢谢 标记。
* 更新 - 更多细节 **
我有两个类,一个称为 Command,另一个称为 Results。我的命令方法有返回结果向量的方法。
命令和结果都使用 pimpl 习惯用法。我希望结果的接口尽可能小。
class Command
{
public:
void getResults( std::vector< Results > & results );
void prepareResults( std::vector< Results > & results );
private:
class CommandImpl *_pimpl;
};
class Results
{
public:
class ResultsImpl;
Results( ResultsImpl * pimpl ) :
_pimpl( impl )
{
}
private
ResultsImpl *_pimpl;
};
现在在 Command::getResults() 中。我将 ResultsImpl 注入到 Results 中。在 Command::prepareResults() 中,我需要访问 ResultsImpl。
M。
I'm implementing several classes using the pimpl idiom and am coming across some design issues.
Firstly, I've always seen pimpl done like this
class Object
{
public:
Visible();
~Visible();
.. etc ..
private:
class ObjectImpl *_pimpl;
};
I have several classes which use this approach and my problem is that several of these classes need access to each others implementation details but the _pimpl pointer is delcared private.
Can anyone see the downside of declaring the _pimpl public. Obviously, if it's public then someone may accidentally (or deliberately) reassign it. (I'm ignoring the fact that "private" could be #defined as "public" and grant access anyway. If you do this then you deserve what you get).
I appreciate that my design may be flawed and would welcome any comments along those lines also.
I'm really loathe to use friends and am not sure they'll even help as you can't forward declare the Object::ObjectImpl without fully defining Object.
i.e.
...
private:
class ObjectImpl *_pimpl;
friend class OtherObject::OtherObjectImpl; // this needs a fully qualified OtherObject
};
Thx
Mark.
* UPDATE - More detail **
I have two classes, one called Command, the other called Results. I have methods on Command which return a vector of Results.
Both Command and Results use the pimpl idiom. I want the interface to Results to be as small as possible.
class Command
{
public:
void getResults( std::vector< Results > & results );
void prepareResults( std::vector< Results > & results );
private:
class CommandImpl *_pimpl;
};
class Results
{
public:
class ResultsImpl;
Results( ResultsImpl * pimpl ) :
_pimpl( impl )
{
}
private
ResultsImpl *_pimpl;
};
Now in Command::getResults(). I inject the ResultsImpl into the Results. in Command::prepareResults() I need access to the ResultsImpl.
M.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我怀疑是否有充分的理由将实现公开:您始终可以使用公共方法公开实现的功能:
除此之外,类应该负责一件事,只负责一件事,并且应该对其他事物具有最低限度的依赖关系课程;如果您认为其他类应该能够访问您的对象的 pimpl,那么您的设计可能有缺陷。
编辑按照作者的更新:虽然你的例子仍然相当模糊(或者至少我无法说出它的全部意图),但你似乎误解了这个习语,现在尝试将其应用到案例中它没有用的地方。正如其他人指出的那样,“P”代表私有。您的结果类没有太多私有实现,因为所有这些都是公共的。因此,要么尝试使用我上面提到的内容,而不是“注入”任何东西,要么完全删除 pimpl 并仅使用 Result 类。如果您的 Result 类接口非常小,以至于它只是指向另一个类的指针,那么在这种情况下它似乎没有多大用处。
I doubt there is a good reason to make the implementation public: you can always expose the implementation's functionality using public methods:
Apart from that a class should be responsible for one thing, one thing only, and should have the bare minimum of dependencies to other classes; if you think other classes should be able to access your Object's pimpl then your design is likely flawed.
edit following the author's update: although your example is still rather vague (or at least I cannot tell the full intent of it), you seem to be misinterpreting the idiom and now try to apply it to a case where it is not usefull. As others pointed out, the 'P' stands for private. Your results class doesn't have much private implementation since all of it is public. So either try to use what I mention above and do not 'inject' anything, or just get rid of the pimpl all together and use just the Result class. If your Result's class interface should be so small that it's nothing but a pointer to another class it doesn't seem to be of much use in this case.
为什么你的类到底依赖于彼此的细节?您可能会重新考虑您的设计。类应该依赖于抽象。
如果您确实认为您的设计正确,那么没有什么可以阻止您提供“源文件私有”标头,例如:
然后在 foo.c 和 bar.c 中 #include foo.impl.h
但再说一遍:通常,
依赖倒置原则:
另外,请务必查看 SOLID 和 GRASP,特别是关于松散耦合的一点。
Why exactly do your classes depend on details of each other? You may re-think your design. Classes should depend on abstractions.
If you really deem your design proper, nothing stops you from providing a "source-file-private" header, like:
and then #include foo.impl.h in both foo.c and bar.c
But again: Generally,
Dependency Inversion Principle:
Also make very sure to check out SOLID and GRASP, especially the point about loose coupling.
只要其他类看不到其类型的定义,将数据成员设为
_pimple
public
就不会给您带来任何好处ObjectImpl
- 这正是 Pimple 想要阻止的事情。相反,您可以做的是向您的
Object
类添加一个私有接口,这将允许友好的类执行它们需要使用Object
执行的任何操作。当然,有关
friend
是一种应尽可能少使用的工具的常见免责声明都适用。Making the the data member
_pimple
public
won't buy you anything as long as those other classes do not see the definition of its typeObjectImpl
- which is the very thing Pimple set out to prevent.What you can do instead is to add a private interface to your
Object
class which will allow befriended classes to do whatever they need to do with anObject
.Of course, the common disclaimers about
friend
being a tool that should be used as rarely as possible all apply.没有必要这样限定朋友。
如果您只使用
友元类OtherObject
,则OtherObject
类可以访问必要的内部结构。就我个人而言,我的 Pimpl 只是一个
struct
(数据束),我将对其进行操作的方法保留在原始类中。It is unnecessary to qualify the friend thusly.
If you just use
friend class OtherObject
, then theOtherObject
class may access the necessary internals.Personally my Pimpl are just a
struct
(bundle of data) and I leave the methods to operate on it in the original class.