C ++虚拟Const函数

时间:2010-09-30 02:56:22

标签: c++

给出以下代码段,

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()?

谢谢

6 个答案:

答案 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_checkoverride关键字在编译时可以检测到这种情况。 Excerpt from wikipedia

  

a的[[base_check]]属性   class / struct意味着任何隐含的   压倒一切会产生一个   编译器错误。任何压倒一切都必须如此   明确标有   [[override]]属性。

最有可能(不太确定语法):

class Derived [[base_check]] : public Base {

    virtual void eval [[override]] () {
        ....
    }
};