让我们考虑两个类A
和B
,其中包含以下接口:
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
继承这样的事情。答案 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”真的需要开始吗?