C ++重载解决方案[重复]
Posted
技术标签:
【中文标题】C ++重载解决方案[重复]【英文标题】:C++ overload resolution [duplicate] 【发布时间】:2010-09-09 11:27:39 【问题描述】:鉴于以下示例,为什么我必须显式使用语句 b->A::DoSomething()
而不仅仅是 b->DoSomething()
?
编译器的重载决议不应该弄清楚我在说哪种方法吗?
我正在使用 Microsoft VS 2005。(注意:在这种情况下使用虚拟没有帮助。)
class A
public:
int DoSomething() return 0;;
;
class B : public A
public:
int DoSomething(int x) return 1;;
;
int main()
B* b = new B();
b->A::DoSomething(); //Why this?
//b->DoSomething(); //Why not this? (Gives compiler error.)
delete b;
return 0;
【问题讨论】:
我正在尝试使用指向 B 类的指针在 A 类中调用 DoSomething()。 【参考方案1】:这两个“重载”不在同一个范围内。默认情况下,编译器只考虑可能的最小名称范围,直到找到名称匹配。参数匹配在之后完成。在您的情况下,这意味着编译器会看到B::DoSomething
。然后它尝试匹配参数列表,但失败了。
一种解决方案是将过载从A
拉到B
的范围内:
class B : public A
public:
using A::DoSomething;
// …
【讨论】:
事实上,如果它们不在同一个作用域内,它们也不叫重载 @Chubsdad:这就是为什么我把这个词放在引号里。并且一旦方法被拉入同一个作用域,它就变成了一个重载。【参考方案2】:重载解析是 C++ 中最丑陋的部分之一
基本上编译器会在 B 的范围内找到名称匹配“DoSomething(int)”,看到参数不匹配,并以错误停止。
可以通过使用 B 类中的 A::DoSomething 来克服
class A
public:
int DoSomething() return 0;
;
class B : public A
public:
using A::DoSomething;
int DoSomething(int x) return 1;
;
int main(int argc, char** argv)
B* b = new B();
// b->A::DoSomething(); // still works, but...
b->DoSomething(); // works now too
delete b;
return 0;
【讨论】:
【参考方案3】:不,这种行为的存在是为了确保您不会被错误地从遥远的基类继承。
要绕过它,您需要通过在 B 类中放置 using A::DoSomething 来告诉编译器您要调用哪个方法。
请参阅 this article 以快速轻松地了解此行为。
【讨论】:
【参考方案4】:派生类中的方法的存在隐藏了基类中具有相同名称(无论参数如何)的所有方法。这样做是为了避免这样的问题:
class A ;
class B :public A
void DoSomething(long) ...
B b;
b.DoSomething(1); // calls B::DoSomething((long)1));
后来有人换了A类:
class A
void DoSomething(int ) ...
现在突然:
B b;
b.DoSomething(1); // calls A::DoSomething(1);
换句话说,如果它不是这样工作的,你无法控制的类 (A) 中的不相关更改可能会默默地影响你的代码的工作方式。
【讨论】:
非常好,我必须说。我看到的大多数答案都谈到了为什么会发生错误以及如何避免它,但你的观点表明了为什么这个功能在现实世界的场景中是必不可少和有用的!【参考方案5】:这与名称解析的工作方式有关。基本上,我们首先找到名称来自的范围,然后我们收集该范围内该名称的所有重载。但是,您的情况的范围是 B 类,而在 B 类中,B::DoSomething 隐藏 A::DOSomething:
3.3.7 名称隐藏 [basic.scope.hiding]
...[剪辑]...
3 在成员函数定义中,本地名称的声明隐藏 同名的类成员的声明;看 basic.scope.class。派生类中成员的声明 (class.derived) 隐藏基类成员的声明 同名;请参阅class.member.lookup。
由于名称隐藏,A::DoSomething 甚至不考虑重载解析
【讨论】:
有实际的规范参考很好。【参考方案6】:当您在派生类中定义函数时,它会隐藏基类中具有该名称的所有函数。如果基类函数是虚拟的并且具有兼容的签名,那么派生类函数也会覆盖基类函数。但是,这不会影响可见性。
您可以使用 using 声明使基类函数可见:
class B : public A
public:
int DoSomething(int x) return 1;;
using A::DoSomething;
;
【讨论】:
【参考方案7】:这不是超载!这是隐藏!
【讨论】:
【参考方案8】:在查找要使用的函数的继承树时,C++ 使用不带参数的名称,一旦找到任何定义,它就会停止,然后检查参数。在给出的示例中,它在 B 类中停止。为了能够做你想做的事情,B 类应该这样定义:
class B : public A
public:
using A::DoSomething;
int DoSomething(int x) return 1;;
;
【讨论】:
【参考方案9】:函数被子类中同名的函数隐藏(但签名不同)。您可以使用 using 语句取消隐藏它,如 using A::DoSomething();
【讨论】:
以上是关于C ++重载解决方案[重复]的主要内容,如果未能解决你的问题,请参考以下文章