C++ 过载解析
鉴于以下示例,为什么我必须显式使用语句 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;
}
Given the following example, why do I have to explicitly use the statement b->A::DoSomething()
rather than just b->DoSomething()
?
Shouldn't the compiler's overload resolution figure out which method I'm talking about?
I'm using Microsoft VS 2005. (Note: using virtual doesn't help in this case.)
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;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
派生类中方法的存在隐藏了基类中具有相同名称(无论参数如何)的所有方法。 这样做是为了避免这样的问题:
后来有人更改了 A 类:
现在突然:
换句话说,如果它不能像这样工作,那么您无法控制的类(A)中的不相关更改可能会默默地影响你的代码是如何工作的。
The presence of a method in a derived class hides all methods with the same name (regardless of parameters) in base classes. This is done to avoid problems like this:
than later someone changes class A:
now suddenly:
In other words, if it didn't work like this, a unrelated change in a class you don't control (A), could silently affect how your code works.
重载解析是 C++ 中最丑陋的部分之一。
基本上,编译器在 B 范围内找到名称匹配“DoSomething(int)”,发现参数不匹配,并因错误而停止。
可以通过使用 B 类中的 A::DoSomething 来克服
Overload resolution is one of the ugliest parts of C++
Basically the compiler finds a name match "DoSomething(int)" in the scope of B, sees the parameters don't match, and stops with an error.
It can be overcome by using the A::DoSomething in class B
这与名称解析的工作方式有关。 基本上,我们首先找到名称来源的范围,然后收集该名称在该范围内的所有重载。 但是,您的情况的范围是 B 类,并且在 B 类中, B::DoSomething 隐藏 A::DOSomething:
3.3.7 名称隐藏 [basic.scope.hiding]
...[snip ]...
3 在成员函数定义中,隐藏了局部名称的声明
具有相同名称的类成员的声明; 看
basic.scope.class。 派生类中成员的声明
(class.衍生) 隐藏以下基类成员的声明
同名; 请参阅class.member.lookup。
由于名称隐藏,A::DoSomething 甚至不被考虑用于重载解析
This has something to do with the way name resolution works. Basically, we first find the scope from which the name comes, and then we collect all overloads for that name in that scope. However, the scope in your case is class B, and in class B, B::DoSomething hides A::DOSomething:
3.3.7 Name hiding [basic.scope.hiding]
...[snip]...
3 In a member function definition, the declaration of a local name hides
the declaration of a member of the class with the same name; see
basic.scope.class. The declaration of a member in a derived class
(class.derived) hides the declaration of a member of a base class of
the same name; see class.member.lookup.
Because of name hiding, A::DoSomething is not even considered for overload resolution
当您在派生类中定义函数时,它会隐藏基类中具有该名称的所有函数。 如果基类函数是虚函数并且具有兼容的签名,则派生类函数也会覆盖基类函数。 不过,这并不影响可见性。
您可以使用 using 声明使基类函数可见:
When you define a function in a derived class then it hides all the functions with that name in the base class. If the base class function is virtual and has a compatible signature then the derived class function also overrides the base class function. However, that doesn't affect the visibility.
You can make the base class function visible with a using declaration:
那不是超载! 那是隐藏!
That's not overloading! That's HIDING!
当在继承树中搜索要使用的函数时,C++ 使用不带参数的名称,一旦找到任何定义,它就会停止,然后检查参数。 在给出的示例中,它停在 B 类中。为了能够执行您要做的事情,B 类应该这样定义:
When searching up the inheritance tree for the function to use, C++ uses the name without arguments, once it has found any definition it stops, then examines the arguments. In the example given, it stops in class B. In order to be able to do what you are after, class B should be defined like this:
该函数被子类中同名的函数隐藏(但具有不同的签名)。 您可以使用 using 语句取消隐藏它,如 using A::DoSomething();
The function is hidden by the function with the same name in the subclass (but with a different signature). You can unhide it by using the using statement, as in using A::DoSomething();
不,这种行为的存在是为了确保您不会错误地从远程基类继承。
为了解决这个问题,您需要通过在 B 类中放置 using A::DoSomething 来告诉编译器您要调用哪个方法。
请参阅本文,快速轻松地了解此行为。
No, this behaviour is present to ensure that you don't get caught out inheriting from distant base classes by mistake.
To get around it, you need to tell the compiler which method you want to call by placing a using A::DoSomething in the B class.
See this article for a quick and easy overview of this behaviour.
这两个“重载”不在同一范围内。 默认情况下,编译器仅考虑可能的最小名称范围,直到找到名称匹配。 之后进行参数匹配。 在您的情况下,这意味着编译器会看到
B::DoSomething
。 然后它尝试匹配参数列表,但失败了。一种解决方案是将重载从
A
拉到B
的范围内:The two “overloads” aren't in the same scope. By default, the compiler only considers the smallest possible name scope until it finds a name match. Argument matching is done afterwards. In your case this means that the compiler sees
B::DoSomething
. It then tries to match the argument list, which fails.One solution would be to pull down the overload from
A
intoB
's scope: