C++ 什么';在C++;?

C++ 什么';在C++;?,c++,C++,GCC手册包含以下警告选项说明-Woverloaded VISUAL: 函数声明对基类隐藏虚拟函数时发出警告。例如,在: struct A { virtual void f(); }; struct B: public A { void f(int); }; A类版本的f隐藏在B中,代码如下: B* b; b->f(); 无法编译 这个代码有什么问题?如果编译失败,为什么是警告而不是错误消息?解决此问题的规范方法是什么?为什么?引入从祖先类型继承的名称会导致该名称隐藏

GCC手册包含以下警告选项说明-Woverloaded VISUAL:

函数声明对基类隐藏虚拟函数时发出警告。例如,在:

struct A {
    virtual void f();
};

struct B: public A {
    void f(int);
};
A
类版本的
f
隐藏在
B
中,代码如下:

B* b;
b->f();
无法编译


这个代码有什么问题?如果编译失败,为什么是警告而不是错误消息?解决此问题的规范方法是什么?为什么?

引入从祖先类型继承的名称会导致该名称隐藏在派生类型中。这就是为什么
b->f()不编译

警告来自
B::f
的声明。编译器告诉您,此新声明不会重载或重写从
A
继承的函数。它将其隐藏在
B
的范围内。有时候你可能想要这个,而且从技术上讲它没有什么问题,这就是为什么它不是一个错误。但是,由于
A::f
隐藏在
B
中,因此不能(静态地)对
B
值/引用调用它

请注意,这与继承的成员函数是虚拟的无关(尽管如果
A::f
不是虚拟的,您不会收到关于声明
B::f
的警告,但是由于同样的原因,两者都将无法编译
B->f()
)。也许更有趣的是,请注意

要同时拥有这两个(在
B
中重载的
f()
),您可以显式地将
f
的名称从
A
带入
B

struct B: public A {
    using A::f;
    void f(int);
};
现在,在
B
中可以看到两个
f()
重载。请注意,
void f()
仍然是虚拟的,但是
void f(int)
没有声明为虚拟的,因此它不是虚拟的

另一个(丑陋的)解决方法是将
B
指针/引用向上投射到
A
指针/引用:

B *b = new B;
static_cast<A*>(b)->f();
B*B=新的B;
静态_cast(b)->f();
或者,使用值而不是指针:

B b;
static_cast<A&>(b).f();
B;
静态_cast(b.f();

这通过
A
类型使用虚拟函数,而该类型不隐藏。

引入从祖先类型继承的名称会导致该名称隐藏在派生类型中。这就是为什么
b->f()不编译

警告来自
B::f
的声明。编译器告诉您,此新声明不会重载或重写从
A
继承的函数。它将其隐藏在
B
的范围内。有时候你可能想要这个,而且从技术上讲它没有什么问题,这就是为什么它不是一个错误。但是,由于
A::f
隐藏在
B
中,因此不能(静态地)对
B
值/引用调用它

请注意,这与继承的成员函数是虚拟的无关(尽管如果
A::f
不是虚拟的,您不会收到关于声明
B::f
的警告,但是由于同样的原因,两者都将无法编译
B->f()
)。也许更有趣的是,请注意

要同时拥有这两个(在
B
中重载的
f()
),您可以显式地将
f
的名称从
A
带入
B

struct B: public A {
    using A::f;
    void f(int);
};
现在,在
B
中可以看到两个
f()
重载。请注意,
void f()
仍然是虚拟的,但是
void f(int)
没有声明为虚拟的,因此它不是虚拟的

另一个(丑陋的)解决方法是将
B
指针/引用向上投射到
A
指针/引用:

B *b = new B;
static_cast<A*>(b)->f();
B*B=新的B;
静态_cast(b)->f();
或者,使用值而不是指针:

B b;
static_cast<A&>(b).f();
B;
静态_cast(b.f();

这通过
A
类型使用虚拟函数,在该类型中虚拟函数不隐藏。

名称查找再次出现-
void B::f(int)
不是一个虚拟函数(不同的签名),它隐藏了
void a::f()的名称需要完整的解释,需要C++的名称查找。<代码> B*B;<代码>尚未初始化,因此
b->f()将是未定义的行为。
b->f()
尝试调用
B::f(int)
,但无法调用,因为它缺少一个参数,因此无法编译。由于参数重载而隐藏基类函数可能是一个boo-boo,这就是编译器提供警告的原因。(编译器选择这样做,这不是标准iirc所要求的。)警告在
void f(int)上B
中的code>声明(因为这可能会导致以后出现错误)
b->f()
实际上应该产生一个错误。不是吗?虽然
b
实际上并没有指向
b
类型的对象(它是垃圾),虽然没有A::f()或b::f(int)的定义,但这两个问题都不是OP所指的问题(事实上,这两个问题中的第一个不会阻止编译)。这与隐藏姓名有关。请参阅cdhowie的回答以明确说明:
B::f
不会过载
A::f
。这两个名称在不同的作用域中定义,因此它们不会重载
不是一个虚拟函数(不同的签名),它隐藏了
void a::f()的名称需要完整的解释,需要C++的名称查找。<代码> B*B;<代码>尚未初始化,因此
b->f()将是未定义的行为。
b->f()
尝试调用
B::f(int)
,但无法调用,因为它缺少一个参数,因此无法编译。由于参数重载而隐藏基类函数可能是一个boo-boo,这就是编译器提供警告的原因。(编译器选择这样做,s不需要它