Nat*_*ath 19 c++ virtual inheritance
我遇到了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
}
Run Code Online (Sandbox Code Playgroud)
我的问题是:为什么不编译?我的理解是C应该从A继承onFoo函数 - 实际上,如果你在B中删除了onFoo的重新定义,那么这会编译 - 但是g ++给出了C没有onFoo()函数的错误.
Dav*_*eas 40
您遇到的问题与名称查找在C++中的工作方式有关.特别是,在解析成员时,编译器将查看正在访问该成员的对象的静态类型.如果在该类中找到标识符,则查找完成并且(在成员函数的情况下)开始重载解析.如果未找到标识符,它将逐个类地爬行层次结构,尝试一次一个级别地定位标识符.
在您的特定情况下,您拥有c->onFoo();并且c属于类型C.编译器没有看到任何onFooin的声明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 );
};
Run Code Online (Sandbox Code Playgroud)
using这里声明的效果是当B查找类时,为了搜索onFoo标识符,指示编译器还要考虑onFoo基类中的所有重载,启用常规查找来查找A::onFoo().
Ben*_*igt 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();
}
Run Code Online (Sandbox Code Playgroud)