【问题标题】:Derive from class declared in private scope派生自在私有范围内声明的类
【发布时间】:2016-07-25 09:07:10
【问题描述】:

我目前正在重构一些遗留代码,并希望将多个 if...elseif... 语句分解为一系列实现各种策略的类。

由于我必须访问原始对象的内部结构,我将把新类声明为嵌套类;由于外部世界的任何人都不应访问它们,因此我更愿意在私有范围内声明它们。

为了尽可能少地暴露实现细节,我想知道是否可以只在头文件中前向声明基本策略类,并将所有子类声明放在实现文件中。代码示例如下:

-- 头文件

class MyUglyClass
{
private:
    class IStrategyBase;
    IStrategyBase* sPtr;
    // class ActualImplementation; // this is what I'd like to avoid
    // class YetAnotherImplementation; // as above
    // blah blah blah
};

-- 实现文件

class MyUglyClass::IStrategyBase
{
    virtual ResultType DoSomething(SomeType someParameter) = 0;
    // could expose some MyUglyClass members, since 
    // derived classes wouldn't inherit friendship
};

class ActualImplementation: public MyUglyClass::IStrategyBase
{
    ResultType DoSomething(SomeType someParameter) override
    {
        // Do actual work
    }
}

class YetAnotherImplementation: public MyUglyClass::IStrategyBase
{
    ResultType DoSomething(SomeType someParameter) override
    {
        // Doing something really tricky & clever for corner cases
    }
}

编译器当然会抱怨,因为IStrategyBase 不可访问;我可以通过将ActualImplementationYetAnotherImplementationIStrategyBase 一起fwd 声明到头文件中来解决此问题,但我宁愿避免这种情况,因为如果需要新策略,我需要更改头文件。

我也可以在公共范围内声明IStrategyBase,但我更愿意将其保密以避免其他人弄乱它。

当然,我假设非 fwd 声明的子类不会继承与 MyUglyClass 的友谊,所以我必须将相关数据暴露给 IStrategyBase 受保护的成员。

有什么方法可以实现我可能会错过的吗?

编辑:

感谢所有发表评论的人,我意识到即使在公共范围内声明,也没有人可以弄乱IStrategyBase 类,因为类定义也会被埋在实现文件中。我现在想知道的是,是否可以让派生类访问MyUglyClass 的内部,而不必将它们与IStrategyBase 一起声明。我想答案是“不”,因为友谊不是遗传的,但也许我还缺少一些 C++ 特权。

【问题讨论】:

  • 就算你把IStrategyBase声明为public,也没有人能惹它。
  • 据我了解,其他人可以从中获得。如果IStrategyBase 暴露了一些MyUglyClass 实现细节,那么任何人都可以访问它们。
  • 你不能派生自一个只声明而不定义的类。
  • 1) 代码示例中没有 friend 这个词。 2) 哪一行产生错误?标头看起来不错,实现需要 IStrategyBase 的 definiton
  • 公开声明。无论如何,实现是私有的。

标签: c++ c++11 inheritance inner-classes


【解决方案1】:

一种可能性(这不是 pimpl 惯用语,只是一种可访问性 hack):

class MyUglyClass
{
private:
    struct Impl; // Is automatically "friend struct Impl;"
    class IStrategyBase;
    IStrategyBase* sPtr;
    // class ActualImplementation; // this is what I'd like to avoid
    // class YetAnotherImplementation; // as above
    // blah blah blah
};

class MyUglyClass::IStrategyBase
{
public:
    virtual int DoSomething(int someParameter) = 0;
    // could expose some MyUglyClass members, since 
    // derived classes wouldn't inherit friendship
};

struct MyUglyClass::Impl
{
    class ActualImplementation: public MyUglyClass::IStrategyBase
    {
        int DoSomething(int someParameter) override
        { (void) someParameter; return 1;}
    };

    class YetAnotherImplementation: public MyUglyClass::IStrategyBase
    {
        int DoSomething(int someParameter) override
        { (void) someParameter; return 2; }
    };
};

int main() {}

【讨论】:

    【解决方案2】:

    如果你想隐藏任何实现细节,你可以使用 pImpl idiom(指向实现的指针)又名不透明指针 https://en.wikipedia.org/wiki/Opaque_pointer 所以你可以像这样更改你的代码

    -- 头文件

    #include <memory>
    
    class MyUglyClass
    {
        MyUglyClass();
        ~MyUglyClass(); // destructor must be only declared to avoid problems
                        // with deleting just forwarded inner class
    private:
        class Impl;
        std::unique_ptr<Impl> pImpl;
    };
    

    -- 实现文件

    class MyUglyClass::Impl
    {
        class IStrategyBase;
        IStrategyBase* sPtr;
        class ActualImplementation; // now these classes safely hidden inside .cpp 
        class YetAnotherImplementation; // Nobody can reach them.
    
    };
    
    class MyUglyClass::Impl::IStrategyBase
    {
        virtual ResultType DoSomething(SomeType someParameter) = 0;
        // could expose some MyUglyClass members, since 
        // derived classes wouldn't inherit friendship
    };
    
    class ActualImplementation: public MyUglyClass::Impl::IStrategyBase
    {
        ResultType DoSomething(SomeType someParameter) override
        {
            // Do actual work
        }
    };
    
    class YetAnotherImplementation: public MyUglyClass::Impl::IStrategyBase
    {
        ResultType DoSomething(SomeType someParameter) override
        {
            // Doing something really tricky & clever for corner cases
        }
    };
    
    MyUglyClass::MyUglyClass() : pImpl(new Impl()) {}
    
    MyUglyClass::~MyUglyClass() {} // let the unique_ptr do its work
    

    【讨论】:

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