请查看以下代码:
#include <iostream>
using namespace std;
class A {
public:
A() {};
virtual void foo(double d) { cout << d << endl; }
virtual void foo(double d, int a) = 0;
};
class B : public A {
public:
B() {};
virtual void foo(double d, int a) { cout << d << endl << a << endl; }
};
int main()
{
B b;
b.foo(3.14);
return 0;
}
编译器(试过g ++和visual c ++ 2008)说没有像B:foo(double)这样的函数。 g ++的确切消息是:
main.cpp:21:错误:没有匹配函数来调用'B :: foo(double)'
它看起来像hiding rule的效果,但在我看来,规则不应该在这里使用,因为我没有覆盖foo(double),并且两个foo方法都在基类中定义。
我知道我可以用
解决问题using A::foo;
派生类B中的声明。
你能解释为什么代码不能编译以及C ++的规则适用于何处?
答案 0 :(得分:5)
命名阴影,而不是特定功能。在foo
中创建B
之后,所有基础foo
(注意,名称!)都会被遮蔽。
答案 1 :(得分:4)
隐藏规则不是覆盖,而是隐藏名称。如果派生类声明了成员函数,则会隐藏具有相同名称的其他基类成员函数。在您的情况下也会发生这种情况。
答案 2 :(得分:2)
当编译器遇到标识符时,查找规则启动并开始搜索该标识符。在具体情况下,使用b.foo
,编译器知道foo
必须是B
或其子类之一的成员。查找规则声明编译器必须从最派生类开始(考虑对象的静态类型)并在层次结构中跟进,并且一旦在一个级别中找到标识符,则仅考虑该级别中的定义,一定不要一直向上看。
B& f(); // might return a B or something derived from B
void test() {
B& b = f(); // static type is B
b.foo(1.0);
}
无论f
返回什么,静态类型都是B
,因此编译器将在B
类中查找并找到B::foo(double,int)
。由于该级别没有其他foo
声明,因此编译器必须尝试使用可用的方法声明来匹配(和失败)函数调用。
重要的是,查找看起来并不是对象,而是按类型查找并向上查看,一旦遇到第一个实例就会切割。
答案 3 :(得分:1)
对我来说看起来非常合理。虽然函数签名对于知道函数是什么很重要,但我可以看到这种行为如何防止非常愚蠢的错误。
正如ereOn建议的那样,使用指令将是一个公平的代价。