我正在阅读Stroustrup的C ++ 0x FAQ,并坚持使用此代码。请考虑以下代码
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;
}
我的理解是当一个类型被继承时,所有受保护的和公共成员都可以从派生类访问。但根据这个例子,看起来我错了。我期待 b.f 将调用基类 f 。我通过改变派生类来获得预期的结果,如
struct B : A
{
using A::f;
void f(int)
{
std::cout << "in int" << std::endl;
}
};
问题
答案 0 :(得分:5)
因为A :: f是“隐藏”而不是“重载”或“被覆盖”。参阅:
http://www.parashift.com/c++-faq-lite/strange-inheritance.html#faq-23.9
答案 1 :(得分:4)
第一个代码可以正常工作,因为c ++可以工作。
重载分辨率遵循一组非常复杂的规则。来自Stroustrup的c ++圣经15.2.2“[A]来自不同基类的函数之间的模糊不能基于参数类型来解决。”
他接着解释了你所描述的“使用”的用法。
这是该语言的设计决定。
我倾向于遵循Stroustrup书而不是标准书,但我确信它就在那里。
[编辑]
这是(来自标准):
第13章
如果为同一范围内的单个名称指定了两个或更多不同的声明,则说该名称为 超载。
然后:
13.2声明匹配
1如果两个函数声明属于同一作用域且具有等效的参数声明(13.1),则它们引用相同的函数。派生类的函数成员与函数成员的范围不同 基类中的相同名称。
答案 2 :(得分:2)
搜索重载决策。一个similar, but not identical question。
答案 3 :(得分:1)
在C ++中,范围内没有重载,派生类中的范围也不例外。 (According to The C++ Programming Language)
有关详细信息,请查看http://www.research.att.com/~bs/bs_faq2.html#overloadderived
答案 4 :(得分:1)
在第一种情况下,派生类方法的基类方法'f'是隐藏。在C ++中,范围内没有超载;这就是它没有被召唤的原因。 C ++标准解释了 部分10.2成员名称查找[class.member.lookup] 中的所有成员名称查找规则。 HTH
答案 5 :(得分:1)
第一个版本的代码应该真正调用B :: f。您在结构“B”中重新定义符号“f”,因此它隐藏了结构“A”中的原始符号“f”。它看起来并不是一种过载。
每当编译器遇到b.f()时,它会在“B”结构中搜索符号“f”。它存在于那里,因此编译器决定调用B :: f(int),将double转换为int。它认为不需要扫描父类以获得更合适的函数......
然而,当你添加“使用A :: f”时,它是一个explict指令,编译器扫描父类的符号“f”。现在,B类有两个重载函数:for int和for double。
我也相信,你可以在不使用原始例子中的“using”指令的情况下编写b.A :: f()......