2008-09-16 62 views
35

给出以下示例,为什么我必须明确使用语句b->A::DoSomething()而不是仅仅是​​?C++过载分辨率

编译器的重载分辨率不应该找出我正在谈论的方法吗?

我使用微软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; 
} 
+0

我试图在类A中使用指向类B的指针调用DoSomething()。 – Abe 2008-09-16 13:22:25

回答

40

两个“重载”是不是在同一个范围内。默认情况下,编译器只会考虑尽可能小的名称范围,直到找到名称匹配为止。事后匹配。在你的情况下,这意味着编译器看到B::DoSomething。然后它尝试匹配失败的参数列表。

一个解决办法是从A拉下过载到B的范围:

class B : public A { 
public: 
    using A::DoSomething; 
    // … 
} 
+1

事实上,如果它们不在同一范围内,它们也不会称为重载 – Chubsdad 2010-11-04 04:18:30

+3

@Chubsdad:这就是为什么我把这个词在引号中。一旦该方法被拉入相同的范围,它就成为一个过载。 – 2010-11-04 09:48:49

13

重载分辨率是C++

最丑陋的部分中的一个基本上编译器发现名称匹配“ DoSomething(int)“在范围内,看到参数不匹配,并停止并出现错误。

它可以通过在B类

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; 
} 
2

使用A :: DoSomething的当在一个派生类定义的函数来克服它然后隐藏了所有与所述基类名的功能。如果基类函数是虚拟的并且具有兼容的签名,那么派生类函数也会覆盖基类函数。但是,这不会影响可视性。

你可以用using声明基类的功能可见:

class B : public A 
{ 
    public: 
    int DoSomething(int x) {return 1;}; 
    using A::DoSomething; 
}; 
1

当搜索了该函数使用继承树,C++使用名称不带参数,一旦发现有任何定义,它停下来,然后检查论据。在给出的例子,它在B类站为了能够做到你是什么之后,B类应定义是这样的:

class B : public A 
{ 
    public: 
    using A::DoSomething; 
    int DoSomething(int x) {return 1;}; 
}; 
1

的功能由隐藏功能使用相同的名称子类(但具有不同的签名)。您可以使用using语句来取消隐藏它,如使用A :: DoSomething();

5

不,这种行为是为了确保你不会被错误地从远处的基类继承。

要解决这个问题,你需要通过在B类中放置一个使用的A :: DoSomething来告诉编译器你想调用哪个方法。

请参阅this article,以便快速轻松地了解此行为。

3

这与名称解析的工作方式有关。基本上,我们首先找到名称的范围,然后我们收集该范围内该名称的所有重载。然而,在您的案件范围B类和B类,B :: DoSomething的隐藏 A :: DoSomething的:

3.3.7名称隐藏[basic.scope.hiding]

.. 。[snip] ...

3在成员函数定义中,本地名称的声明隐藏了 声明该类的成员具有相同的名称;见 basic.scope.class。派生类 (class.derived)中成员的声明隐藏了同名基类成员 的声明;见class.member.lookup。由于名称隐藏

,A :: DoSomething的甚至没有考虑重载

+0

具有实际的规格参考是好的。 – Sam 2012-01-04 21:32:02

2

那不是超载!这是隐藏的!

5

派生类中存在的方法隐藏了基类中所有具有相同名称(不管参数)的方法。这样做是为了避免这样的问题:

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),可能会默默地影响你的代码的工作方式。