在子类中覆盖时如何调用私有虚拟基类实现
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();
一起使用,但由于Default
s 声明这是private
,所以这里会失败。
显然一种解决方案是将其从private
更改为protected
,但我想问一下是否还有其他方法?我不想让任何孩子直接调用此函数,而是将其限制为通过 Base
或 Default
类中已定义的虚函数发起的调用。
是否有一些选项或修饰符允许仅允许来自子类的成员函数调用,前提是它们位于(相同的)覆盖虚拟成员函数中?
【问题讨论】:
我认为不,这是不可能的。这正是protected
的用法,允许从具有public
继承的孩子访问
唯一能想到的就是把派生类做成friend
。
@songyuanyao 在这种情况下,我认为friend
比protected
更邪恶;它将允许访问可能更多,并且需要修改基类,每个新的派生类都需要类似的访问......
【参考方案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
是邪恶的。以上是关于在子类中覆盖时如何调用私有虚拟基类实现的主要内容,如果未能解决你的问题,请参考以下文章