使用私有基本功能覆盖公共虚拟功能?

时间:2017-01-23 14:13:01

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

让我们考虑两个类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私有基本功能不起作用以覆盖虚拟。从那以后,有两个问题:

  • 有没有办法让这项工作正如我认为可能有效?
  • 为什么编译器会接受此代码有效?正如我所看到的,现在有两个start()函数在C中具有完全相同的签名,但编译器看起来很好,只调用A::start()

编辑:一些准确性:

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

2 个答案:

答案 0 :(得分:5)

  

有没有办法让这项工作正如我认为可能有效?

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

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

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

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

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()

现在,在using B::start()class C执行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中的函数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() }

abs

答案 1 :(得分:0)

我认为你可能会混淆“公共”和“私人”的含义。在C ++继承上下文中,这仅仅意味着一切都知道'C'是'A',而对于'B'类型,只有其他'C'对象可以访问'C'对象的父方法('B'方法)

第二部分是关于继承歧义。 没有 using B::start;继承确实是模棱两可的,不会编译(去c.start()时),所以事实上在你的例子中添加该语句不是可选的(使用A或B )如果你不想经常使用合格的路径。

我不清楚您是否希望c()->start();调用'A'方法或'B'方法,但using语句将根据您的需要确定它。你编写代码的方式有点不确定 - “A”真的需要开始吗?