【问题标题】:Stopping inheritance from base class after nth inheritance in C++在 C++ 中的第 n 次继承后停止从基类继承
【发布时间】:2019-01-07 04:42:44
【问题描述】:

我有一个问题,我只需要继承一次基类。之后我想阻止任何人继承这个类。有人可以解释一下如何实现这一点。此外,如果基类被继承的次数是 n 次(例如 1 ..10),那么通用的方法是什么。

我知道在基类中使用朋友类可以在一定程度上解决我的问题。但我觉得这很笨拙。我也读过Restrict inheritance to desired number of classes at compile-time。我无法完全理解答案。

有人可以建议我在 C++ 编译时限制继承的更好方法吗?

【问题讨论】:

  • 我发现继承树的深度是理解类的主要障碍。很高兴你问如何限制它。
  • @MarkRansom 据我所知,OP 正在询问如何限制继承树的宽度,而不是深度。
  • 您真的需要允许一定数量的未知派生类吗?或者您需要防止任何不在特定预期实现中的其他派生类?你能说一下为什么吗?这听起来像是 X-Y 问题;可能有更好的方法来防止其他派生类可能造成的任何伤害。
  • “而且如果它可以在运行时限制继承就好了。” 你什么意思?我们无法在运行时创建类/层次结构...
  • 这听起来像是一个错误的功能。记录你的类做了什么以及它打算如何使用。如果有人滥用它,那是他们的问题,而不是你的问题。

标签: c++ inheritance


【解决方案1】:

目前基类由内部团队继承一次。现在这个类可供第三方使用。但是我不希望他们继承这个基类。所以这是问题陈述

问题在于 C++ 没有提供任何直接以这种方式限制继承的方法。

指向实现习惯用法的指针可能会帮助您解决问题:

class PublicToUser final
{
    class PrivateToUser;
    std::unique_ptr<PrivateToUser> implementation;
public:
    // ***
};

现在它将是实际继承的私有内部类,但这可以完全隐藏起来,即。 e.您根本不需要将该基类公开给用户——不可见的将不会被继承...

【讨论】:

    【解决方案2】:

    我有一个问题,我只需要继承一次基类。之后我想阻止任何人继承这个类。

    从 C++11 开始,您可以简单地使用 final 来防止类被进一步子类化:

    class BaseClass { };
    
    class DoNotInheritClass final : public BaseClass { };
    

    为了限制单个基类的子类数量,显然没有 C++ 内置功能。您需要通过添加一些静态变量来自己跟踪子类。这是一个现有的答案:Counting instances of individual derived classes

    【讨论】:

    • 我需要从基类继承一次。因此,这无济于事。这将不允许任何人从基类继承一次。
    • 所以您只想从BaseClass 继承一次,并且不能再向下继承,对吧?
    • No.. 此外,我希望它像问题中提到的那样通用。假设我希望基类被继承两次或三次,那么方法是什么
    • 看到这个答案然后stackoverflow.com/questions/772655/…
    【解决方案3】:

    如果您不能使用其他答案中的 PIMPL 解决方案,这里有一些想法可能会有所帮助。它们要么基于 CRTP,要么基于构造函数标记:

    #include <type_traits>
    
    struct A;
    
    template<typename T>
    struct Base final {
    
    };
    
    // Specialise Base for A to be non-final
    template<>
    struct Base<A> {};
    
    struct A : Base<A> {};
    

    第一个 sn-p 背后的想法是拥有一个 final CRTP-base 并为类 A 添加一个非最终特化。显然,这允许用户(或您自己)在需要时定义更多允许的派生,但可以防止意外继承。

    template<char...>
    struct password {};
    
    struct Base2 {
    
        Base2() = delete;
    
        template<char... pwd>
        Base2(password<pwd...> ) {
            using expected_pwd = password<'t','o','p','s','e','c','r','e','t'>;
            static_assert(std::is_same_v<password<pwd...>, expected_pwd>);
        }
    };
    
    struct A2 : Base2 {
    
        A2() : Base2(password<'t','o','p','s','e','c','r','e','t'>{}) {}
    };
    
    struct A3 : Base2 {
    
        // No way to construct Base2 without correct password :)
        A3() : Base2(password<'b', 'a', 'm', 'm'>{}) {}
    };
    

    第二个 sn-p 背后的想法(这更像是一个笑话而不是真正的代码......)是用 password 结构替换 Base2 类的默认构造函数。在实现中,您检查给构造函数的密码。在派生类的实现中,您只需使用正确的密码调用Base2 构造函数。当然,您的用户可以从基类派生,但由于密码完全隐藏在实现中,因此无法构造派生对象:)

    int main(){
    
        auto a = A{};
        auto a2 = A2{};
        auto a3 = A3{};  // fails
        return 0;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-12-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-16
      相关资源
      最近更新 更多