给出以下代码段,
class Base
{
public:
virtual void eval() const
{
std::cout<<"Base Const Eval\n";
}
};
class Derived:public Base
{
public:
void eval()
{
std::cout<<"Derived Non-Const Eval\n";
}
};
int main()
{
Derived d;
Base* pB=&d;
pB->eval(); //This will call the Base eval()
return 0;
}
为什么pB-&gt; eval()将调用Base :: eval()?
谢谢
答案 0 :(得分:8)
在Derived
类中,eval的原型与Base
中虚拟函数的原型不匹配。所以它不会覆盖虚函数。
Base::eval() const;
Derived::eval(); //No const.
如果为Derived::eval()
添加const,则应该获得虚拟行为。
答案 1 :(得分:8)
你可以在脑海中翻译:
virtual void Base::eval() const;
void Derived::eval() ;
到
void eval(const Base *this, size_t vtable_offset);
void eval(Derived *this);
并通过检查看到第二个符号与第一个符号的匹配程度。
答案 2 :(得分:6)
这是因为一个被声明为const而另一个被声明为const。一个功能被另一个隐藏。 Derived中的函数将其隐藏在Base中,因为它们具有相同的名称,而它们不是同一个函数。
我的编译器在这里发出警告,你的吗?
答案 3 :(得分:5)
$ 10.3 / 2-“如果是虚拟成员函数 vf在类Base和in中声明 派生类,直接派生或 成员之间的间接来自Base 函数vf具有相同的名称, parameter-type-list(8.3.5), cv-qualification 和refqualifier(或 Base :: vf是没有相同的 声明,然后Derived :: vf也是 虚拟的(无论是否如此 声明)并且覆盖111 基:: VF“。
111)具有相同名称的功能但是 不同的参数列表(第13条) 作为虚函数不是 必然虚拟而不是 覆盖。使用虚拟 声明中的说明符 压倒一切的功能是合法的但是 冗余(具有空语义)。 访问控制(第11条)不是 在确定压倒一切时考虑过。
顺便说一句,请注意它没有谈论访问规范。因此,重写函数的基类和派生类访问说明符可能不同
这意味着Derived :: eval不会覆盖Base :: eval,因为它们的cv资格不同。
答案 4 :(得分:2)
const
是函数签名的一部分。为了覆盖一个函数,覆盖必须与基本版本具有完全相同的签名 - 在这种情况下它不会。
请考虑调用代码不需要了解Derived
的任何内容 - 它正在调用const
上的Base
函数。你不会期望这个调用会在非const函数中结束,这可能会改变关于类的内容。
答案 5 :(得分:2)
在C ++ 0x中,使用base_check
和override
关键字在编译时可以检测到这种情况。 Excerpt from wikipedia:
a的[[base_check]]属性 class / struct意味着任何隐含的 压倒一切会产生一个 编译器错误。任何压倒一切都必须如此 明确标有 [[override]]属性。
最有可能(不太确定语法):
class Derived [[base_check]] : public Base {
virtual void eval [[override]] () {
....
}
};