我正在使用pimpl习语实现几个类,并且遇到了一些设计问题。
首先,我一直看到pimpl像这样做了
class Object
{
public:
Visible();
~Visible();
.. etc ..
private:
class ObjectImpl *_pimpl;
};
我有几个使用这种方法的类,我的问题是这些类中的一些需要访问彼此的实现细节,但_pimpl指针是私有的。
任何人都可以看到声明_pimpl公开的缺点。显然,如果它是公开的,那么有人可能会意外(或故意)重新分配它。 (我忽略了这样一个事实:“私人”可能被#defined定义为“公共”并且无论如何都会授予访问权限。如果你这样做,那么你应该得到你得到的东西。)
我很欣赏我的设计可能存在缺陷,并欢迎任何评论。
我真的不喜欢使用朋友,我不确定他们甚至会帮忙,因为你不能在没有完全定义Object的情况下转发声明Object :: ObjectImpl。
即
...
private:
class ObjectImpl *_pimpl;
friend class OtherObject::OtherObjectImpl; // this needs a fully qualified OtherObject
};
THX 标记
*更新 - 更多细节**
我有两个类,一个叫做Command,另一个叫做Results。我在Command上有方法返回结果向量。
命令和结果都使用了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注入结果。在Command :: prepareResults()中我需要访问ResultsImpl。
微米。
答案 0 :(得分:7)
我怀疑是否有充分理由将实现公开:您始终可以使用公共方法公开实现的功能:
class Object
{
public:
Object();
~Object();
int GetImplementationDetail();
private:
std::unique_ptr< ObjectImpl > _pimpl;
};
int Object::GetImplementationDetail()
{
return pimpl->GetImplementationDetail();
}
除了一个类应该只负责一件事,一件事,并且应该对其他类有最小的依赖性;如果您认为其他类应该能够访问您的Object的pimpl,那么您的设计可能存在缺陷。
在作者更新之后编辑:虽然你的例子仍然相当模糊(或者至少我不能说出它的完整意图),但你似乎误解了这个成语,现在尝试应用它对于没用的情况。正如其他人指出的那样,'P'代表私人。您的结果类没有太多私有实现,因为它们都是公共的。所以要么尝试使用我上面提到的并且不要“注入”任何东西,要么只是一起摆脱pimpl并仅使用Result类。如果你的Result的类接口应该是如此之小,以至于它只是一个指向另一个类的指针,在这种情况下似乎并没有多大用处。
答案 1 :(得分:1)
为什么你的课程完全取决于彼此的细节?你可能会重新考虑你的设计。类应该依赖于抽象。
如果你真的认为你的设计正确,没有什么可以阻止你提供“源文件 - 私有”标题,如:
include/
foo.h
src/
foo.impl.h
foo.c
bar.c
然后在foo.c和bar.c中#include foo.impl.h
foo.c:
#include "foo.impl.h"
...
bar.c:
#include "foo.impl.h"
...
但同样:一般来说,
<强> Dependency Inversion Principle 强>:
一个。高级模块不应该依赖于低级模块。两者都应该取决于抽象。
B中。抽象不应该依赖于细节。细节应取决于抽象。
答案 2 :(得分:0)
只要其他类看不到其类型_pimple
的定义,制作数据成员public
ObjectImpl
就不会为您带来任何好处 - 这是Pimple为阻止 而设置的内容。
您可以做的是为您的Object
课程添加一个私人界面,这样可以让合作班级为Object
做任何他们需要做的事情。
当然,关于friend
作为应尽可能少使用的工具的常见免责声明均适用。
答案 3 :(得分:0)
因此没有必要对朋友进行资格认定。
如果您只使用friend class OtherObject
,则OtherObject
类可以访问必要的内部。
就个人而言,我的Pimpl只是一个struct
(数据包),我将这些方法保留在原始类中进行操作。