5

我正在使用 pimpl 习惯用法实现几个类,并且遇到了一些设计问题。

首先,我总是看到 pimpl 这样做

class Object
{
public:
    Visible();
    ~Visible();
 .. etc ..
private:
    class ObjectImpl *_pimpl;
};

我有几个使用这种方法的类,我的问题是其中几个类需要访问彼此的实现细节,但是 _pimpl 指针是私有的。

任何人都可以看到将 _pimpl 公开的不利之处。显然,如果它是公开的,那么有人可能会意外(或故意)重新分配它。(我忽略了“私人”可以被#定义为“公共”并授予访问权限这一事实。如果你这样做,那么你应该得到你所得到的)。

我很欣赏我的设计可能存在缺陷,并且也欢迎任何关于这些方面的评论。

我真的很讨厌使用朋友,并且不确定他们是否会提供帮助,因为您无法在没有完全定义 Object 的情况下转发声明 Object::ObjectImpl。

IE

 ...
 private:
    class ObjectImpl *_pimpl;
    friend class OtherObject::OtherObjectImpl; // this needs a fully qualified OtherObject
};

谢谢马克。

* 更新 - 更多细节 **

我有两个类,一个叫做命令,另一个叫做结果。我在 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。

M。

4

4 回答 4

7

我怀疑公开实现是否有充分的理由:您始终可以使用公共方法公开实现的功能:

class Object
{
public:
   Object();
  ~Object();

  int GetImplementationDetail();

private:
  std::unique_ptr< ObjectImpl > _pimpl;
};

int Object::GetImplementationDetail()
{
  return pimpl->GetImplementationDetail();
}

除此之外,一个类应该负责一件事,只负责一件事,并且应该对其他类具有最低限度的依赖;如果您认为其他类应该能够访问您的对象的 pimpl,那么您的设计可能有缺陷。

在作者更新之后进行编辑:尽管您的示例仍然相当模糊(或者至少我无法说出它的全部意图),但您似乎误解了这个成语,现在尝试将它应用于它没有用的情况。正如其他人指出的那样,“P”代表私有。您的结果类没有太多私有实现,因为它都是公共的。因此,要么尝试使用我上面提到的内容并且不要“注入”任何东西,要么一起摆脱 pimpl 并只使用 Result 类。如果您的 Result 的类接口应该很小,以至于它只是指向另一个类的指针,在这种情况下它似乎没有多大用处。

于 2011-06-24T10:19:07.720 回答
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"
    ...

但又一次:一般来说,

依赖倒置原则

A. 高级模块不应依赖于低级模块。两者都应该依赖于抽象。

B. 抽象不应依赖于细节。细节应该取决于抽象。

还要确保检查SOLIDGRASP,尤其是关于松散耦合的要点。

于 2011-06-24T10:20:54.807 回答
0

_pimple public只要那些其他类看不到它的类型的定义,制作数据成员就不会给你带来任何好处ObjectImpl——这正是 Pimple 所要防止的

相反,您可以做的是向您的Object类添加一个私有接口,这将允许结识的类使用Object.

当然,关于friend作为一种应尽可能少使用的工具的常见免责声明都适用。

于 2011-06-24T10:21:35.380 回答
0

没有必要这样限定朋友。

如果您只使用friend class OtherObject,那么OtherObject该类可能会访问必要的内部。

就我个人而言,我的 Pimpl 只是一个struct(数据包),我将在原始类中对其进行操作的方法。

于 2011-06-24T10:27:17.303 回答