防止公众使用用作私人基类的类

Prevent public uses of a class used as a private base class

本文关键字:基类      更新时间:2023-10-16

即使使用 base 类也只能确保"我的"代码只能使用"我的"代码?(如果不用用作基类,我可以将其作为我的一个类的privateprotected嵌套类)

如果我想指出在我的一个类中使用基类是一个实现细节,我可以使用私人基类:

 class Base
 {
      ...
 }
 class Derived: private Base
 {
 public:
      Derived(...): Base{...} {... };
      ...
 }

对于我使用Base类的Derived班级的客户,

尚不明显
 #include "Derived.h"
 void client() {
    Derived d{...};
    Base *b = static_cast< Base * >(&d);// error
    ...
 }

但是,请想象Base类是如此专业,混乱或棘手的使用,以至于我不希望代码的客户将其用作基类或创建该类的对象。从某种意义上说,我希望它是我的某些代码的"私有",因此这样的客户端代码失败了:

 #include "Derived.h"
 class Client: Base// error wanted here
 {
 public:
    Client(...): Base{...} {...};
    ...
 }
 void client()
 {
    Derived d{...};// OK
    Base b{...};// error wanted here
    Client c{...};// error wanted here
 }

我该怎么做?

实际上,我问我如何才能实现诸如Java的软件包私有类之类的东西,这些类别仅适用于同一"软件包"(模块)中的其他类,但不能被"软件包"外的代码使用。

您可以通过将"私人"实体放入 detail名称空间中,按照惯例"强制"。许多受欢迎的库(例如Boost)这样做:

namespace detail
{
    class Base { /* ... */ };
}
class Derived : private detail::Base
{
    /* ... */
};

当将模块标准化时,此问题将得到正确解决,因为您将能够控制哪些实体被导出并且哪些是实施详细信息。

这不能像在Java中直接完成。如果仅是避免混乱的问题,则可以将Base移入命名空间中,该名称空间被您的代码客户端忽略,例如:

namespace hidden {
  class Base {
    ..
  };
}
class Derived : private hidden::Base {
  ...
};

相反,如果您真的想避免使用Base的可能性,那么如果您打算将Base用作多个类的父母(随着时间的推移可能会有所不同),那将是一个很难的故事。您可以给Base一个private构造函数,并指出您的每个派生类都是Basefriend

class Hider {
  private:
    Hider() = delete;
    class Base {
      ..
    };
  friend class Derived;
};
class Derived : Hider::Base {
  ..
};

当然,这需要您要从Base派生的每个新类的手动维护。

如果您想100%执行它,并且不喜欢"请不要使用以'_'开头的东西"的Python方法,那么我相信这是您的端口通话:

class Dave;
class MyPrivateBaseClasses {
  private:
    MyPrivateBaseClasses();    // ensure nothing can use this class
    class BaseClassA {};
    friend Dave;
};
class Dave : public/private MyPrivateBaseClasses::BaseClassA
{};

肯定 - 这意味着您必须成为所有想要使用它的东西,但它确实为您提供了想要的东西;100%使用基本体的保护人。