2010-09-30 85 views
6

考虑下面的代码片段,C++虚拟const函数

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->的eval()将调用基:: eval()函数?

谢谢

回答

6

这是因为一个被声明为const而另一个不是。一个功能被另一个隐藏。 Derived中的函数隐藏Base中的函数,因为它们具有相同的名称,而它们不是相同的函数。

我的编译器在这里给出警告,你的?

+0

好奇:什么编译器?什么警告选项? – Arun 2010-09-30 03:23:50

+0

如果您在大多数编译器上打开警告。 – 2010-09-30 03:35:28

8

在您的Derived类中,eval的原型与Base中虚拟函数的原型不匹配。所以它不会覆盖虚函数。

Base::eval() const; 
Derived::eval(); //No const. 

如果为Derived::eval()添加常量,则应该获得虚拟行为。

2

const是功能签名的一部分。为了覆盖函数,覆盖必须与基本版本具有完全相同的签名 - 在这种情况下,它不会。

考虑到调用代码不需要知道任何关于Derived的信息 - 它调用Base上的const函数。你不会期望这个调用会在非const函数中发生,这可能会改变关于这个类的东西。

5

$ 10.3/2-“如果虚拟成员函数 VF在类Base和在 声明的类派生的,直接或 从基地成员 函数VF具有相同名称, 衍生间接参数类型列表(8.3.5), CV-资格,和refqualifier(或 不存在相同)基地:: Vf为 声明,那么派生:: VF也 虚拟(不论它是否是如此 宣布)和它覆盖111 Base :: vf。“

111)具有相同名称的功能,但 不同的参数列表(第13) 作为一个虚拟函数不是 一定虚拟并且不 覆盖。在 覆盖函数声明中使用虚拟 说明符是合法的,但是 冗余(具有空的语义)。 访问控制(条款11)不是 在确定重写时需要考虑。

另外,请注意,它不会谈论访问规范。因此,覆盖功能的基类和派生类访问说明符可能不同

这意味着Derived :: eval不会覆盖Base :: eval,因为它们的cv资格不同。

8

你可以在你的心中翻译:

virtual void Base::eval() const; 
void Derived::eval() ; 

void eval(const Base *this, size_t vtable_offset); 
void eval(Derived *this); 

,并通过检查看到第二怎能少了第一次的签名相匹配。

+0

+1:良好的心理模型。 (你可能想要标记你的代码。) – Arun 2010-09-30 03:22:06

2

在C++ 0x中,在编译时使用base_checkoverride关键字可以检测到这种情况。 Excerpt from wikipedia

在 类/结构的[[base_check]]属性意味着任何隐式 压倒一切将产生一个 编译错误。任何覆盖必须是 明确标记为 [[override]]属性。

最有可能(不是很肯定的语法):

class Derived [[base_check]] : public Base { 

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