C++虚函数被隐藏

发布于 2024-11-24 07:35:23 字数 448 浏览 0 评论 0原文

我在 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

水染的天色ゝ 2024-12-01 07:36:18

我猜你错过了在 class B 中添加这个:

struct B : A
{
    using A::onFoo;
    virtual void onFoo(int i) {}
    void onFoo() {} //This line missing in your code.
};

现在可以编译了!

I guess you have missed adding this in class B:

struct B : A
{
    using A::onFoo;
    virtual void onFoo(int i) {}
    void onFoo() {} //This line missing in your code.
};

Now this compiles!

橘寄 2024-12-01 07:36:12

您忘记了 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.

霞映澄塘 2024-12-01 07:36:10

A 类和 B 类的方法应该是公共的。那,你在每个类声明的末尾缺少分号。

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
}

Methods on class A and B should be public. That, and you are missing semi-colons at the end of each class declaration.

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
}
她比我温柔 2024-12-01 07:36:09

这是名称隐藏,基本上只有声明的重写存在于 B 中,而 A 中的其他重载被隐藏。

This is name hiding, basically only the declared overrides exist in B and the other overloads in A are hidden.

只有一腔孤勇 2024-12-01 07:36:07

如果您希望基类成员重载派生类成员,则需要使用 using

struct A
{
   virtual void onFoo() {}
   virtual void onFoo(int i) {}
};

struct B : A
{
    using A::onFoo;
    virtual void onFoo(int i) {}
};

struct C : B
{
};


int main()
{
    C* c = new C();
    c->onFoo();
}

If you want base class members to overload derived class members, you want to use using:

struct A
{
   virtual void onFoo() {}
   virtual void onFoo(int i) {}
};

struct B : A
{
    using A::onFoo;
    virtual void onFoo(int i) {}
};

struct C : B
{
};


int main()
{
    C* c = new C();
    c->onFoo();
}
仅此而已 2024-12-01 07:36:05

您遇到的问题与 C++ 中名称查找的工作方式有关。特别是,在解析成员时,编译器将查看正在访问该成员的对象的静态类型。如果在该类中找到标识符,则查找完成并且(在成员函数的情况下)重载决策开始。如果未找到标识符,它将逐类爬行层次结构,尝试一次定位一层标识符。

在您的特定情况下,您有 c->onFoo(); 并且 c 的类型为 C。编译器在 C 中看不到任何 onFoo 声明,因此它在层次结构中继续向上。当编译器检查B时,它发现该级别有一个void onFoo(int i)声明,因此它停止查找,并尝试重载解析。此时,由于参数不一致,重载决策失败。

事实上,B 级别存在 void onFoo(int) 声明,具有隐藏任何基中其余重载的效果类,因为它将停止查找。请注意,这是不合格查找的问题,该函数仍然存在并且适用于该对象,但不会通过常规查找找到(您仍然可以将其称为 c->A::onFoo()< /代码>)。

至于如何处理隐藏,最简单的方法是使用using声明将函数带入作用域:

class B : A {
public:
   using A::onFoo; // All A::onFoo overloads are *considered* here
   void onFoo( int );
};

这里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(); and c is of type C. The compiler does not see any declaration of onFoo in C, so it continues upwards in the hierarchy. When the compiler checks B, it sees that there is a declaration of void 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 at B 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 as c->A::onFoo()).

As of how to deal with hiding, the simplest way is by employing the using declaration to bring the functions into scope:

class B : A {
public:
   using A::onFoo; // All A::onFoo overloads are *considered* here
   void onFoo( int );
};

The effect of the using declaration here is that when the B class is looked up, in search for the onFoo identifier, the compiler is instructed to also consider all overloads of onFoo in the base class, enabling regular lookup to find A::onFoo().

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文