C++虚函数被隐藏
我在 C++ 继承方面遇到问题。
我有一个类层次结构:
class A {
public:
virtual void onFoo() {}
virtual void onFoo(int i) {}
};
class B : public A {
public:
virtual void onFoo(int i) {}
};
class C : public B {
};
int main() {
C* c = new C();
c->onFoo(); //Compile error - doesn't exist
}
我的问题是:为什么它不能编译?我的理解是,C 应该从 A 继承两个 onFoo 函数 - 事实上,如果您删除 B 中 onFoo 的重新定义,则可以编译 - 但 g++ 会给出一个错误,指出 C 没有 onFoo() 函数。
I'm having a problem with C++ inheritance.
I have a class hierarchy:
class A {
public:
virtual void onFoo() {}
virtual void onFoo(int i) {}
};
class B : public A {
public:
virtual void onFoo(int i) {}
};
class C : public B {
};
int main() {
C* c = new C();
c->onFoo(); //Compile error - doesn't exist
}
My question is: why doesn't this compile? My understanding is that C should inherit both onFoo functions from A - and in fact, this compiles if you remove the redefinition of onFoo in B - but g++ gives an error that C has no onFoo() function.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
我猜你错过了在
class B
中添加这个:现在可以编译了!
I guess you have missed adding this in
class B
:Now this compiles!
您忘记了 A 类和 B 类中方法之前的
public:
修饰符。因此 onFoo 方法是私有的,因此在这些类之外的任何地方都不可见。You forgot
public:
modifier before methods in both class A and B. Therefore method onFoo is private and thus not visible anywhere outside these classes.A 类和 B 类的方法应该是公共的。那,你在每个类声明的末尾缺少分号。
Methods on class A and B should be public. That, and you are missing semi-colons at the end of each class declaration.
这是名称隐藏,基本上只有声明的重写存在于 B 中,而 A 中的其他重载被隐藏。
This is name hiding, basically only the declared overrides exist in B and the other overloads in A are hidden.
如果您希望基类成员重载派生类成员,则需要使用
using
:If you want base class members to overload derived class members, you want to use
using
:您遇到的问题与 C++ 中名称查找的工作方式有关。特别是,在解析成员时,编译器将查看正在访问该成员的对象的静态类型。如果在该类中找到标识符,则查找完成并且(在成员函数的情况下)重载决策开始。如果未找到标识符,它将逐类爬行层次结构,尝试一次定位一层标识符。
在您的特定情况下,您有
c->onFoo();
并且c
的类型为C
。编译器在C
中看不到任何onFoo
声明,因此它在层次结构中继续向上。当编译器检查B
时,它发现该级别有一个void onFoo(int i)
声明,因此它停止查找,并尝试重载解析。此时,由于参数不一致,重载决策失败。事实上,
B
级别存在void onFoo(int)
声明,具有隐藏任何基中其余重载的效果类,因为它将停止查找。请注意,这是不合格查找的问题,该函数仍然存在并且适用于该对象,但不会通过常规查找找到(您仍然可以将其称为c->A::onFoo()< /代码>)。
至于如何处理隐藏,最简单的方法是使用using声明将函数带入作用域:
这里
using
声明的效果是,当<查找 code>B 类,在搜索onFoo
标识符时,指示编译器还考虑基类中onFoo
的所有重载,从而启用定期查找以找到A::onFoo()
。The issue that you are experiencing is related to how name lookup works in C++. In particular, when resolving a member, the compiler will look into the static type of the object on which the member is being accessed. If the identifier is found in that class, then lookup completes and (in the case of member functions) overload resolution starts. If the identifier is not found, it will crawl up the hierarchy, class by class, trying to locate the identifier one level at a time.
In your particular case, you have
c->onFoo();
andc
is of typeC
. The compiler does not see any declaration ofonFoo
inC
, so it continues upwards in the hierarchy. When the compiler checksB
, it sees that there is a declaration ofvoid onFoo(int i)
at that level, so it stops lookup, and tries overload resolution. At this time, the overload resolution fails due to the inconsistency in the arguments.The fact that a declaration of
void onFoo(int)
is present atB
level has the effect of hiding the rest of the overloads in any base class, as it will stop lookup. Note that this is a problem with unqualified lookup, the function is still there and applicable to the object, but will not be found by regular lookup (you can still call it asc->A::onFoo()
).As of how to deal with hiding, the simplest way is by employing the using declaration to bring the functions into scope:
The effect of the
using
declaration here is that when theB
class is looked up, in search for theonFoo
identifier, the compiler is instructed to also consider all overloads ofonFoo
in the base class, enabling regular lookup to findA::onFoo()
.