我知道这不是关于这个主题的第一个问题,但我读到的所有其他相关问题(和答案)都有点离题了。取代码
#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"并没有覆盖,如所述,同名的上行类成员函数:两个同名的成员函数有不同的签名-所以它不是覆盖)。
这就是语言的设计方式——内部作用域中的名称隐藏外部作用域中的名称。这里,派生类充当内部作用域,基类充当外部作用域。
如果函数在同一作用域中,则它们会被认为是重载,但这并不重要。隐藏作用于名称,而不是单个函数。
您可以通过显式地将名称添加到派生类中来覆盖默认值:
class Derived : public Base {
public:
using Base::methodA; // Now it is visible!
void methodA(int i) { cout << "Derived.methodA(int i)" << endl ;}
};
这意味着它只是在基类中隐藏同名成员函数的成员函数名,并且不考虑签名
正确的。这就是这种语言的设计方式。我也不太喜欢这个语言设计特性。但是它有很好的文档,你没有选择
我想你已经明白了。它被称为名称隐藏,这就是该语言的构造方式。但我不认为这是一种不便,因为当你花时间学习c++时,你最终会对这些约定感到很舒服。当你定义一个与基类方法同名的非虚方法时它会在派生类中隐藏基类方法所以你会得到
的错误 obj.methodA();
要避免在派生类中隐藏基类方法,可以这样做:
obj.Base::methodA();
更多信息:http://www.programmerinterview.com/index.php/c-cplusplus/c-name-hiding/