2009-06-17 78 views
7

我正在阅读Stroustrup的C++ 0x FAQ,并被这段代码困住了。请看下面的代码继承时的范围规则 - C++

struct A 
{ 
    void f(double) 
    { 
     std::cout << "in double" << std::endl; 
    } 
}; 

struct B : A 
{ 
    void f(int) 
    { 
     std::cout << "in int" << std::endl; 
    } 
}; 


int main() 
{ 
    A a; a.f(10.10); // as expected, A.f will get called 
    B b; b.f(10.10); // This calls b.f and we lose the .10 here 
    return 0; 
} 

当一个类型是继承我的理解是,所有的protected和public成员将来自派生类访问。但根据这个例子,看起来我错了。我期待b.f将调用基类f。我通过改变像

struct B : A 
{ 
    using A::f; 
    void f(int) 
    { 
     std::cout << "in int" << std::endl; 
    } 
}; 

问题

  1. 为什么它不是第一个代码工作的派生类中预期的结果?
  2. C++标准中的哪一部分描述了所有这些范围规则?
+0

qood问题.. + 1 – Warrior 2009-06-17 08:43:18

回答

4

第一个代码的工作原理是C++被设计用于工作。

重载解析遵循一组非常复杂的规则。来自Stroustrup的C++ bible 15.2.2“[A]来自不同基类的函数之间的混淆不会基于参数类型来解析。”

他继续解释如您所描述的“使用”的使用。

这是这个语言的设计决定。

我倾向于遵循Stroustrup书而不是标准,但我确定它在那里。

[编辑]

在这里它是(从标):

第13章

当两个或更多个不同的声明为单个名称在同一范围内指定,该名称是说是 重载。

然后:

13.2声明匹配的同名

1两个函数声明是指相同的功能,如果他们是在相同的范围,并具有相当的参数声明(13.1)。派生类的函数成员与基类中的相同名称的函数成员 不在同一个作用域中。

+0

将是值得加入固定的例子(即。使用A :: foo)。 – 2009-06-17 10:15:34

1

在第一种情况,所述基类的方法“f”被由派生类的方法隐藏。在C++中,跨作用域不会超载;这就是为什么它没有被调用。 C++标准解释了部分中的所有成员名称查找规则。10.2成员名称查找[class.member.lookup]。 HTH

1

代码的第一个版本确实应该调用B :: F。您在结构“B”中重新定义符号“f”,因此它将结构“A”中的原始符号“f”隐藏起来。它看起来并不是一个超载。

只要编译器符合b.f(),它就会在“B”结构中搜索符号“f”。它出现在那里,所以编译器决定调用B :: f(int),将double转换为int。它认为没有必要扫描父类以获得更适合的功能...

但是,当您添加“using A :: f”时,它是编译器的一个explict指令,用于扫描父类的符号“ F”。现在,B类有两个重载函数:int和double。

我也相信,你可以写BA :: F(),而不使用“使用”,在最初的例子指令......