【问题标题】:Member function hidden in derived class隐藏在派生类中的成员函数
【发布时间】:2010-07-05 07:53:47
【问题描述】:

请看下面的代码:

#include <iostream>
using namespace std;

class A {
  public:
    A() {};    
    virtual void foo(double d) { cout << d << endl; }
    virtual void foo(double d, int a) = 0;
  };

class B : public A {
  public: 
    B() {};
    virtual void foo(double d, int a) { cout << d << endl << a << endl; }  
  };

int main()
  {
  B b;
  b.foo(3.14);
  return 0;
  }

编译器(尝试过 g++ 和 visual c++ 2008)说没有像 B:foo(double) 这样的函数。 g++ 的确切信息是:

main.cpp:21: 错误:没有匹配函数调用‘B::foo(double)’

它看起来像hiding rule 的效果,但我认为这里不应该使用该规则,因为我没有覆盖 foo(double) 并且两个 foo 方法都定义在基类中。

我知道我可以用

解决问题
using A::foo;

派生类B中的声明。

你能解释一下为什么代码不能编译,C++ 的哪些规则在这里适用吗?

【问题讨论】:

  • 这只是“名称隐藏”问题。为什么不能只使用using A::foo 子句?
  • 不是完全重复,但这里讨论的问题相同:stackoverflow.com/questions/72010/c-overload-resolution
  • 在这种情况下,如果您想实现纯虚拟 foo 方法,您必须重新定义名称为 foo 的所有方法,或者为纯虚拟方法和实现的方法选择不同的名称。
  • 嘿嘿,B中的foo(double, int)不用指定是虚的。

标签: c++


【解决方案1】:

隐藏规则不是关于覆盖,而是关于隐藏名称。如果派生类声明了一个成员函数,这会隐藏其他同名的基类成员函数。这也发生在你的情况。

【讨论】:

    【解决方案2】:

    命名影子,而不是具体功能。一旦您在B 中创建了foo,所有基本foo(请注意,按名称!)都会被遮蔽。

    【讨论】:

      【解决方案3】:

      当编译器遇到标识符时,查找规则会启动并开始搜索该标识符。在您的具体情况下,使用b.foo,编译器知道foo 必须是B 或其子类之一的成员。查找规则规定编译器必须从派生最多的类开始(考虑对象的静态类型)并在层次结构中跟进,并且一旦在一个级别中找到标识符,将只考虑该级别中的定义,它不能一直向上看。

      B& f(); // might return a B or something derived from B
      void test() {
         B& b = f(); // static type is B
         b.foo(1.0);
      }
      

      不管f返回什么,静态类型都是B,所以编译器会在B类中查找B::foo(double,int)。由于该级别没有其他 foo 声明,编译器必须尝试将函数调用与可用的方法声明匹配(并失败)。

      重要的是查找不查找对象,而是按类型查找并向上查找,一旦遇到第一个实例就进行切割。

      【讨论】:

        【解决方案4】:

        在我看来完全合理。虽然函数签名对于知道函数是什么很重要,但我可以看到这种行为如何防止非常愚蠢的错误。

        正如 ereOn 所建议的,使用指令将是一个公平的代价。

        【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-03-13
        • 1970-01-01
        • 2021-02-12
        • 2021-11-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多