【问题标题】:C++ inheritance and name hiding [duplicate]C ++继承和名称隐藏[重复]
【发布时间】:2016-01-01 23:27:44
【问题描述】:

我知道这不是关于这个主题的第一个问题,但据我说,我读到的所有其他相关问题(和答案)都有些不合时宜。 拿代码

#include <iostream>

using namespace std ;

class Base {
public:
    void methodA() { cout << "Base.methodA()" << endl ;}
};

class Derived : public Base {
public:
    void methodA(int i) { cout << "Derived.methodA(int i)" << endl ;}
};

int  main()
{
  Derived obj;
  obj.methodA();
}

使用最新版本的 g++ 编译此代码会出现错误

no matching function for call to 'Derived::methodA()'

正是因为这个错误,我才来到 Stackoverflow 寻找答案。 但没有一个答案让我信服。 这两种方法的签名在区分它们时没有歧义,编译器应该能够在基类中选择方法。 注释掉

class Derived : public Base {
//public:
//    void methodA(int i) { cout << "Derived.methodA(int i)" << endl ;}
};

并且代码按预期工作。 这意味着在基类中隐藏同名成员函数只是成员函数名称,并且不考虑签名,就像函数名称没有被修改一样(在这种情况下,修改应该解决任何歧义)。 其他人在类似的问题中写道,这违背了 C++ 的精神(以及我补充说的面向对象),我完全同意他的观点。这是函数重载的一个限制,我真的没有看到任何合理的理由。

显然问题已关闭,所以我无法在阅读答案后添加回复,只能编辑我自己的初始问题。 我相当肯定(但我无法证明这一点)在较旧的 C++ 编译器中,我最初问题中的代码可以毫无问题地编译(然后执行)。 我的观点是,我真的看不出这种语言设计(正如回复中所说的那样)选择背后的基本原理。在这种情况下,编译器已经获得了所有信息,以便采取适当的措施,这正是我所期望的。否则看起来,通过语言设计选择,它被选择不考虑成员函数的签名,这听起来很奇怪。 我在上面提到的“programmerinterview”上阅读了这篇文章,但它没有解释是什么促使了这种语言设计选择(此外,该文章末尾示例代码中的“GrandChildClass”中的“someFunction”不会覆盖,如前所述,同名的上升类成员函数:两个同名的成员函数具有不同的签名 - 所以它不是覆盖)。

【问题讨论】:

  • 这似乎更像是一个咆哮而不是一个问题。在这种情况下,您似乎了解 C++ 的行为。
  • 换一种说法,其他人可能会说这是函数重载的一个优势......这是语言在一天结束时定义的内容。
  • 投票重新开放。如果有人有一本旧书,他们可以找到有关它的报价。作为记录,我认为被拒绝的不良行为和当前规范都略有偏差。我想他有可能曾经有一个编译器做我希望标准做的事情,那就是匹配传递的参数数量。
  • stroustrup.com/bs_faq2.html#overloadderived 解释了为什么它需要以这种方式工作。

标签: c++ inheritance name-hiding


【解决方案1】:

这就是语言的设计方式 - 内部范围内的名称隐藏外部范围内的名称。这里派生类充当内部作用域,基类充当外部作用域。

如果函数在同一范围内,它们将被视为重载这一事实并不重要。隐藏对名称起作用,而不是对单个函数起作用。

您可以通过将名称显式添加到派生类来覆盖默认值:

class Derived : public Base {
public:
    using Base::methodA;   // Now it is visible!

    void methodA(int i) { cout << "Derived.methodA(int i)" << endl ;}
};

【讨论】:

  • 可能想澄清一下类层次结构中“内部”和“外部”范围的含义。
  • 基类中有两个methodA的情况是否有效?
【解决方案2】:

这表示在基类中隐藏同名成员函数只是成员函数名,不考虑签名

正确。这就是语言的设计方式。我也不太喜欢这种语言设计功能。但它有据可查,您别无选择。

【讨论】:

    【解决方案3】:

    我想你已经明白了。它被称为名称隐藏,这就是语言的制作方式。但我不认为这是一种不便,因为当您花时间使用 C++ 时,您最终会对这些约定感到非常满意。当您定义与 Base 方法同名的非虚拟方法时,它会在 Derived 类中隐藏 Base 类方法,因此您会收到错误

    obj.methodA();

    为了避免在派生类中隐藏基类方法,您可以这样做:

    obj.Base::methodA();

    欲了解更多信息:http://www.programmerinterview.com/index.php/c-cplusplus/c-name-hiding/

    【讨论】:

    • 隐藏规则会影响名称,因此也会影响虚函数。
    • @Peter 隐藏规则不会影响虚函数,因为调用是在运行时使用类的虚表解析的,其中包含指向被调用虚函数的最派生定义的指针。在虚函数调用解析的情况下,会考虑整个函数签名(名称和参数),而不仅仅是函数名称。
    • @RishitChaudhary - 你误解了我的观点。在这个问题给出的例子中,如果Base::methodA() 被设为虚拟,它仍然被Derived::methodA(int) 隐藏。如果Derived::MethodA(int) 是虚拟的,那将是真的。
    • @Peter 你是说使用 ::() 会覆盖虚函数的行为并在编译时本身解决函数调用?
    • @RishitChaudhary - 是的,隐藏规则导致“案例 1”成为可诊断错误。
    猜你喜欢
    • 2011-02-05
    • 1970-01-01
    • 1970-01-01
    • 2012-02-13
    • 1970-01-01
    • 2018-11-15
    • 1970-01-01
    • 1970-01-01
    • 2017-09-21
    相关资源
    最近更新 更多