我遇到了C ++继承问题。
我有一个类层次结构:
class A {
public:
virtual void onFoo() {}
virtual void onFoo(int i) {}
};
class B : public A {
public:
virtual void onFoo(int i) {}
};
class C : public B {
};
int main() {
C* c = new C();
c->onFoo(); //Compile error - doesn't exist
}
我的问题是:为什么这不编译?我的理解是C应该从A继承onFoo函数 - 实际上,如果你在B中删除了onFoo的重新定义,那么这会编译 - 但是g ++给出了一个C没有onFoo()函数的错误。
答案 0 :(得分:37)
您遇到的问题与名称查找在C ++中的工作方式有关。特别是,在解析成员时,编译器将查看正在访问该成员的对象的静态类型。如果在该类中找到标识符,则查找完成并且(在成员函数的情况下)开始重载解析。如果找不到标识符,它将逐类爬行层次结构,尝试一次找到标识符一个级别。
在您的特定情况下,c->onFoo();
和c
类型为C
。编译器在onFoo
中没有看到C
的任何声明,因此它在层次结构中继续向上。当编译器检查B
时,它会发现该级别存在void onFoo(int i)
的声明,因此它会停止查找,并尝试重载解析。此时,由于参数不一致,重载决策失败。
在void onFoo(int)
级别存在B
声明的事实会导致隐藏任何基类中的其余重载,因为它会停止查找。请注意,这是一个非限定查找的问题,该函数仍然存在并适用于该对象,但不会通过常规查找找到(您仍然可以将其称为c->A::onFoo()
)。
关于如何处理隐藏,最简单的方法是使用using声明将函数纳入范围:
class B : A {
public:
using A::onFoo; // All A::onFoo overloads are *considered* here
void onFoo( int );
};
此处using
声明的效果是,当查找B
类时,为了搜索onFoo
标识符,指示编译器也考虑{的所有重载。 {1}}在基类中,启用常规查找以查找onFoo
。
答案 1 :(得分:12)
如果希望基类成员重载派生类成员,则需要使用using
:
struct A
{
virtual void onFoo() {}
virtual void onFoo(int i) {}
};
struct B : A
{
using A::onFoo;
virtual void onFoo(int i) {}
};
struct C : B
{
};
int main()
{
C* c = new C();
c->onFoo();
}
答案 2 :(得分:7)
这是名称隐藏,基本上只有B中存在已声明的覆盖,并且A中的其他重载都是隐藏的。
答案 3 :(得分:2)
A类和B类的方法应该是公开的。那,并且你在每个类声明的末尾都缺少分号。
class A {
public:
virtual void onFoo() {}
virtual void onFoo(int i) {}
};
class B : public A {
public:
virtual void onFoo(int i) {}
};
class C : public B {
};
int main() {
C* c = new C();
c->onFoo(); //Compile error - doesn't exist
}
答案 4 :(得分:1)
您在A类和B类中的方法之前忘记了public:
修饰符。因此onFoo方法是私有的,因此在这些类之外的任何地方都不可见。
答案 5 :(得分:-2)
我猜你错过了在class B
中添加的内容:
struct B : A
{
using A::onFoo;
virtual void onFoo(int i) {}
void onFoo() {} //This line missing in your code.
};
现在编译了!