【问题标题】:C++ Virtual function being hiddenC++ 虚函数被隐藏
【发布时间】:2011-10-07 07:29:12
【问题描述】:

我遇到了 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() 函数。

【问题讨论】:

    标签: c++ inheritance virtual


    【解决方案1】:

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

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

    现在编译!

    【讨论】:

      【解决方案2】:

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

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

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

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

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

      这里using声明的效果是,当查找B类时,在搜索onFoo标识符时,指示编译器也考虑基类中onFoo的所有重载,启用定期查找以查找A::onFoo()

      【讨论】:

        【解决方案3】:

        如果你想让基类成员重载派生类成员,你想使用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();
        }
        

        【讨论】:

          【解决方案4】:

          您在 A 类和 B 类的方法之前忘记了 public: 修饰符。因此方法 onFoo 是私有的,因此在这些类之外的任何地方都不可见。

          【讨论】:

          • 哎呀——这不是问题所在,只是我把问题抄写错了。编辑修复
          【解决方案5】:

          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
          }
          

          【讨论】:

          • 这些是有效点,但您的“修复”也无法编译。
          【解决方案6】:

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

          【讨论】:

            猜你喜欢
            • 2011-05-07
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-11-13
            • 2013-02-25
            • 2011-05-23
            • 2012-10-21
            相关资源
            最近更新 更多