【问题标题】:Override public virtual function with private base function?用私有基函数覆盖公共虚函数?
【发布时间】:2017-06-08 01:57:09
【问题描述】:

让我们考虑两个类AB,其接口如下:

class A {
public:
    virtual void start() {} //default implementation does nothing
};

class B {
public:
    void start() {/*do some stuff*/}
};

然后是从两者继承的第三个类,A 公开,因为它实现了这个“接口”,而B 私下,因为那是实现细节。

然而,在这个特定的实现中,start() 只需要包含对B::start() 的调用。所以我想我可以使用快捷方式并执行以下操作:

class C: public A, private B {
public:
    using B::start;
};

并完成它,但显然它不起作用。所以我得到using 私有基本函数不能工作以覆盖虚拟。由此,有两个问题:

  • 有什么方法可以使这项工作像我认为的那样有效吗?
  • 为什么编译器会接受此代码为有效代码?正如我所看到的,现在C 中有两个具有完全相同签名的start() 函数,但编译器似乎很好,只调用A::start()

编辑:一些精度:

  • 目标是通过A指针来操作C对象。
  • 我目前正在使用一个只调用 B::start() 的简单函数,我特别想知道 using 声明是否确实可以“覆盖”虚拟,如果不能,如何允许这两个函数共存。李>
  • 为了简单起见,我可能省略了 virtual 继承之类的一些内容。

【问题讨论】:

  • 不清楚你在期待什么。 C c; c.start(); 应该调用 B::start()
  • 它在这里工作:ideone.com/e71lnB
  • @Rama 我想这更多是关于 A* a = &c; a->开始();为您的 ideone 样本
  • 您在寻找void C::start() override { B::start(); }吗?
  • @curiousguy 嗯,既然你这么说,我可能确实用错了这个词。使用指令仅适用于命名空间的东西,我应该使用的是“使用声明”。谢谢。

标签: c++ overriding virtual-functions using-declaration private-inheritance


【解决方案1】:

有什么方法可以使这项工作像我认为的那样有效吗?

您应该重写成员函数并显式调用B::start()

class C: public A, private B {
public:
    void start() override { B::start(); }
};

为什么编译器会接受此代码为有效代码?正如我在那里看到的 现在是两个 start() 函数,在 C 中具有完全相同的签名,并且 然而编译器似乎很好,只调用A::start()

你说得对,C 中有两个可访问的成员函数(A::start()B::start())。在class C 中,如果不覆盖start() 或通过执行using ...::start() 使任何基类的start() 可见,则在尝试使用来自对象的未验证名称查找调用成员函数时会出现歧义错误C

class A {
public:
    virtual void start() { std::cout << "From A\n"; }
};

class B {
public:
    void start() { std::cout << "From B\n"; }
};

class C: public A, private B {
};

int main(){
    A* a = new C();
    a->start();       //Ok, calls A::start()

    C* c = new C();
    c->start();       //Error, ambiguous         
}

要解决这个问题,您必须使用限定名称,例如:

    C* c = new C();
    c->A::start();       //Ok, calls A::start()

现在,在class C 中执行using B::start() 只需声明start() 以引用B::start(),只要从C 的对象中使用此类名称即可

class A {
public:
    virtual void start() { std::cout << "From A\n"; }
};

class B {
public:
    void start() { std::cout << "From B\n"; }
};

class C: public A, private B {
public:
     using B::start();
};

int main(){
    A* a = new C();
    a->start();       //Ok, calls A::start()

    C* c = new C();
    c->start();       //Ok, calls B::start()
}

using B::start 使函数 void B::start()C 中可见,它不会覆盖它。调用make上述所有非限定成员函数调用,调用B::start(),你应该重写C中的成员函数,并使其调用B::start()

class A {
public:
    virtual void start() { std::cout << "From A\n"; }
};

class B {
public:
    void start() { std::cout << "From B\n"; }
};

class C: public A, private B {
public:
    void start() override { B::start(); }
};

int main(){
    A* a = new C();
    a->start();         //Ok, calls C::start() which in turn calls B::start()
                        //    ^^^^^^^^^^^^^^^^ - by virtual dispatch

    C* c = new C();
    c->start();         //Ok, calls C::start() which in turn calls B::start()

}

【讨论】:

  • 是的,我现在正在使用您首先提到的解决方案。我想更具体地说,是否有办法让using 指令“覆盖”虚函数。
  • @JBL, using 不影响 vtables,它主要是 C++ 中用于处理名称的编译时机制,不能用于覆盖,另一方面覆盖对类vtable中的成员函数指针
  • 是的,我现在明白了。感谢您的解释!
  • 不使用overwrite关键字时得到相同的结果:void start() { B::start(); }
猜你喜欢
  • 2010-10-03
  • 2018-07-24
  • 2013-10-04
  • 2011-02-18
  • 2015-09-27
  • 2016-10-08
  • 2021-10-22
  • 2015-04-20
相关资源
最近更新 更多