【问题标题】:What are benefits of using PrivateClass containing data of the Class?使用包含类数据的 PrivateClass 有什么好处?
【发布时间】:2012-12-29 11:12:28
【问题描述】:
class MyClassPrivate
{
//My members.
};    

//and then
class MyClass {
private:
 MyClassPrivate* const d;
};

使用这种“模式”的原因是什么?如何正确调用?

【问题讨论】:

    标签: c++ architecture design-patterns


    【解决方案1】:

    这称为“指向实现”或“pimpl”。见http://en.wikibooks.org/wiki/C++_Programming/Idioms#Pointer_To_Implementation_.28pImpl.29

    当您使用此模式时,您将转发声明实现类,并在其他地方声明主体,即:

    // header
    class MyClassPrivate;
    class MyClass {
    public:
      MyClass();
      ~MyClass();
    private:
      MyClassPrivate* const d;
    };
    
    // cpp
    class MyClassPrivate {
    };
    MyClass::MyClass() : d(new MyClassPrivate) {}
    MyClass::~MyClass() { delete d; }
    

    这样做的好处是MyClass的实现不会暴露给MyClass的其他用户。如果实现发生变化,MyClass 的其他用户不需要重新编译。任何必须为成员包含的头文件也不需要公开,从而缩短了编译时间。

    【讨论】:

    【解决方案2】:

    当您想将接口与实施分开时,您可以将其用于PIMPL idiom

    许多设计模式也使用指向私有属性的“指针”,例如策略模式。此模式允许您在运行时选择不同的算法。

    此外,如果您使数据的操作遵循相同的接口,您可以将数据封装在私有类中,使该类成为层次结构的一部分,并在运行时(或编译时)在不同的数据实现之间切换对于这个问题 :))。

    一个很好的例子是保存多边形数据的几何类。每个多边形都提供对点的访问,您还可以删除多边形边并进行各种其他拓扑操作。如果为 Polygon 类提供抽象基类,提供 deletePoint、addPoint、swapEdge 等方法,可以测试不同的 Polygon 实现。

    您可以直接将多边形定义为点类型的列表,并将点存储在不同的容器(列表或向量)中。 Polygon 类可以通过间接寻址 定义,其中多边形实际上是点列表的 ID 列表(我说的是一般意义上的列表)。这样,您可以测试 PolygonGeometry 类的不同算法,并了解它们如何与不同的 Polygon 实现一起工作。

    这背后有一个设计原则:优先组合胜于继承。每当您使用组合并且依赖于在运行时确定的类型时,您将拥有一个私有属性指针。

    【讨论】:

      【解决方案3】:

      使用最多的是Pimlp成语。

      Pimpl 成语描述了一种制作头文件的方法 无法改变。你经常听到诸如“避免改变你的 公共接口!”所以你可以修改你的私有接口,但是如何 当你的头文件定义私有时,你能避免重新编译吗 方法。这就是 Pimpl 所做的——减少编译损坏 你的私有界面改变了[3]。

      来自Here

      好处:

      1. 更改类的私有成员变量不需要重新编译依赖它的类,因此编译时间更快,并且 FragileBinaryInterfaceProblem 减少了。
      2. 头文件不需要#include 在私有成员变量中“按值”使用的类,因此编译时间更快。
      3. 这有点像 SmallTalk 自动处理类的方式...更纯粹的封装。

      缺点:

      1. 实施者需要做更多的工作。
      2. 不适用于需要通过子类访问的“受保护”成员。
      3. 阅读代码有点困难,因为头文件中不再有一些信息。
      4. 由于指针间接,运行时性能略有下降,尤其是在函数调用是虚拟的情况下(间接分支的分支预测通常很差)。

      怎么做:

      1. 将所有私有成员变量放入一个结构中。
      2. 将结构定义放入 .cpp 文件中。
      3. 在头文件中,只放结构体的ForwardDeclaration。
      4. 在类定义中,将指向结构的(智能)指针声明为唯一的私有成员变量。
      5. 类的构造函数需要创建结构体。
      6. 类的析构函数需要销毁结构(可能由于使用了智能指针而隐式销毁)。
      7. 赋值运算符和 CopyConstructor 需要适当地复制结构,否则将被禁用。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-10-02
        • 1970-01-01
        • 2018-10-11
        • 2011-04-21
        • 1970-01-01
        相关资源
        最近更新 更多