在子类中覆盖时如何调用私有虚拟基类实现

Posted

技术标签:

【中文标题】在子类中覆盖时如何调用私有虚拟基类实现【英文标题】:How to call private virtual base class implementation when overriding in child class 【发布时间】:2019-09-27 05:57:46 【问题描述】:

我有一个这样的类层次结构:

class Base

public:
  void start()  init(); 
private:
  virtual void init() = 0;
;

class Default : public Base

private:
  virtual void init() override /*default implementation*/;
;

class Special : public Default

private:
  virtual void init() override final /*specialized implementation*/;

如果我在 Special 类型的对象上调用 start(),这会正常工作;

现在我有一个案例,在Special 类的实现中,我想调用Default 类的实现。 通常这可以与Default::init(); 一起使用,但由于Defaults 声明这是private,所以这里会失败。

显然一种解决方案是将其从private 更改为protected,但我想问一下是否还有其他方法?我不想让任何孩子直接调用此函数,而是将其限制为通过 BaseDefault 类中已定义的虚函数发起的调用。

是否有一些选项或修饰符允许仅允许来自子类的成员函数调用,前提是它们位于(相同的)覆盖虚拟成员函数中?

【问题讨论】:

我认为不,这是不可能的。这正是protected的用法,允许从具有public继承的孩子访问 唯一能想到的就是把派生类做成friend @songyuanyao 在这种情况下,我认为friendprotected 更邪恶;它将允许访问可能更多,并且需要修改基类,每个新的派生类都需要类似的访问...... 【参考方案1】:

C++ 没有提供直接实现这一点的方法,因此您必须解决问题,例如。 G。在下面的一段代码中。

好吧,如果你绝对想要。我个人宁愿退回到使函数受到保护,记录它们的用途以及何时被调用,然后只相信派生类可以正确地做这些事情。这最终使界面保持清洁,并且不依赖于相当不寻常(也许是丑陋)的模式(实际上通过 this 两次)。

class Base

public:
    virtual ~Base()  
    void start()
    
        InitProxy p(*this);
        init(p);
    
protected:
    class InitProxy
    
    public:
        InitProxy(InitProxy const&) = delete;
        void init()
        
            m_base.Base::init(*this);
        
    private:
        friend class Base;
        Base& m_base;
        InitProxy(Base& base)
            : m_base(base)
         
    ;
private:
    virtual void init(InitProxy& proxy)  
;

class Derived : public Base

    void init(InitProxy& proxy) override
    
        proxy.init();
    
;

如果您想将此约束应用于多个函数,您可以让代理接受一个成员函数指针,这样您就不必分别为每个函数重新编写代理。如果函数参数不同,您可能需要从那时起制作模板。

【讨论】:

【参考方案2】:

转发声明Special,并使其成为Default的朋友:

class Base

public:
  void start()  init(); 
private:
  virtual void init() = 0;
;

class Special;  // Forward declaration
class Default : public Base

private:
  virtual void init() override /*default implementation*/
  friend class Special; // Friend declaration
;

class Special : public Default

private:
  virtual void init() override final 
      Default::init();
      /*Other implementation*/
  
;

【讨论】:

然而friend 是邪恶的。

以上是关于在子类中覆盖时如何调用私有虚拟基类实现的主要内容,如果未能解决你的问题,请参考以下文章

c ++使基类在子类中使用覆盖的方法

C++ 为啥我可以从派生类调用基类的私有虚函数?

在基类中编写需要在子类中覆盖的方法实现?

java中私有的属性、静态成员可以被子类继承吗?

如何在私有和受保护的访问修饰符之间进行选择以封装基类和子类之间的成员?

多态实现的机制