使用私有继承来隐藏实现是一个好主意吗?

时间:2012-09-21 01:32:59

标签: c++ design-patterns inheritance pimpl-idiom

e.g。

// Implementation.
struct PrivatePoint {
  void SomePrivateMethod();

  double x;
  double y;
}

struct Point : private PrivatePoint {
  double DistanceTo(const Point& other) const;
}

这似乎与Pimpl idiom类似。这有两个我非常喜欢的优点:

  1. SomePrivateMethod是可测试的。如果SomePrivateMethod在Point中被声明为private,则无法从测试中调用它。如果你在Point中声明它是公共的或受保护的,测试就可以调用它,但Point的常规用户也是如此。
  2. 与Pimpl习惯用法相比,访问私有数据更容易阅读和写入,因为您不必通过指针,例如。
  3. Point::DistanceTo(const Point& other) {
      SomePrivateMethod();
    
      double dx = other.x - x;
      double dy = other.y - y;
      return sqrt(dx * dx + dy * dy);
    }
    

    VS

    Point::DistanceTo(const Point& other) {
      ptr->SomePrivateMethod();
    
      double dx = other.ptr->x - ptr->x;
      double dy = other.ptr->y - ptr->y;
      return sqrt(dx * dx + dy * dy);
    }
    

3 个答案:

答案 0 :(得分:2)

你的建议有一些缺点......

用户可以将自己联系到“私人”课程。

pimpl习惯用法的主要目的是作为编译防火墙,允许私有成员在实现文件中指定,因此可以在不触及标题的情况下进行更改,并且需要/触发客户端重新编译,这与仅重新链接不同,这是如果更新是动态加载的库,则更快,甚至可能不需要涉及客户端应用程序的任何操作。你失去了这些好处。

  

SomePrivateMethod是可测试的。如果SomePrivateMethod在Point中被声明为private,则无法从测试中调用它。如果你在Point中声明它是公共的或受保护的,那么测试就可以调用它,但Point的常规用户也是如此。

还有其他方便的hackish选项:例如 - 您可以使用测试代码声明友谊,或使用预处理器构建公开数据的测试模式。

答案 1 :(得分:1)

私有继承与组合(和pimpl)非常相似,但有一些缺点需要考虑:

  1. 您需要在公共标头中显示PrivatePoint定义。这引入了对PrivatePoint的编译时依赖性,并且每次更改PrivatePoint时都要求Point的客户端重新编译。对于pimpl,情况并非如此,只需转发声明PrivatePoint就可以了: struct PrivatePoint;

  2. 封装是周末的。通过私有继承,扩展Point的客户端能够实现自己的SomePrivateMethod版本(C ++允许覆盖私有虚方法)。这不是您的示例中的问题,但如果SomePrivateMethod被声明为虚拟

  3. 如果你使用了pimpl,你也可以轻松地对PrivatePoint进行单元测试。

答案 2 :(得分:0)

不,无论如何你必须发布声明基类的头文件。私有继承保护您或您的用户免受对数据/方法的不必要的访问。