【问题标题】:Scoping rules when inheriting - C++继承时的范围规则 - C++
【发布时间】:2009-06-17 08:28:13
【问题描述】:

我正在阅读 Stroustrup 的 C++0x 常见问题解答并被此代码卡住了。考虑以下代码

struct A
{
    void f(double)
    {
        std::cout << "in double" << std::endl;
    }
};

struct B : A
{
    void f(int)
    {
        std::cout << "in int" << std::endl;
    }
};


int main()
{
    A a; a.f(10.10);  // as expected, A.f will get called
    B b; b.f(10.10);  // This calls b.f and we lose the .10 here
    return 0;
}

我的理解是当一个类型被继承时,所有受保护的和公共的成员都可以从派生类中访问。但是根据这个例子,看起来我错了。我期待 b.f 将调用基类 f。我通过更改派生类得到了预期的结果,如

struct B : A
{
    using A::f;
    void f(int)
    {
        std::cout << "in int" << std::endl;
    }
};

问题

  1. 为什么它在第一个代码中不起作用?
  2. C++ 标准的哪个部分描述了所有这些范围规则?

【问题讨论】:

    标签: c++ scope


    【解决方案1】:

    这是因为 A::f 是“隐藏”而不是“重载”或“覆盖”。参考:

    http://www.parashift.com/c++-faq-lite/strange-inheritance.html#faq-23.9

    【讨论】:

      【解决方案2】:

      第一个代码按照 c++ 的设计工作。

      重载解析遵循一组非常复杂的规则。来自 Stroustrup 的 c++ 圣经 15.2.2 “[A] 来自不同基类的函数之间的歧义不能根据参数类型来解决。”

      他接着解释了你所描述的“使用”的用法。

      这是该语言的设计决策。

      我倾向于遵循 Stroustrup 的书而不是标准,但我确信它在那里。

      [编辑]

      这里是(来自标准):

      第 13 章

      当在同一范围内为单个名称指定两个或多个不同的声明时,该名称被称为 重载。

      然后:

      13.2 声明匹配

      1 如果两个同名函数声明在同一范围内并且具有等效的参数声明 (13.1),则它们引用同一个函数。派生类的函数成员与 基类中的同名。

      【讨论】:

      • 值得添加固定示例(即使用 A::foo)。
      【解决方案3】:

      搜索重载分辨率。一个similar, but not identical question

      【讨论】:

        【解决方案4】:

        在 C++ 中,没有跨作用域的重载,派生类中的作用域也不例外。 (According to The C++ Programming Language)

        欲了解更多信息,请查看http://www.research.att.com/~bs/bs_faq2.html#overloadderived

        【讨论】:

          【解决方案5】:

          在第一种情况下,基类方法“f”被派生类方法隐藏。在 C++ 中,没有跨范围的重载;这就是它不被调用的原因。 C++ 标准在第 10.2 节成员名称查找 [class.member.lookup] 中解释了所有成员名称查找规则。 高温

          【讨论】:

            【解决方案6】:

            第一个版本的代码应该真正调用 B::f。您在结构“B”中重新定义了符号“f”,因此它从结构“A”中隐藏了原始符号“f”。这并不是看起来的过载。

            每当编译器遇到 b.f() 时,它都会在“B”结构中搜索符号“f”。它存在于此,因此编译器决定调用 B::f(int),将 double 转换为 int。它认为不需要扫描父类以获得更合适的功能...

            然而,当您添加“使用 A::f”时,编译器会显式指令扫描父类中的符号“f”。现在,B 类有两个重载函数:for int 和 for double。

            我也相信,您可以编写 b.A::f() 而不在原始示例中使用“using”指令...

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2017-10-12
              • 2016-01-13
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多