2010-09-30 87 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]]() { 
     .... 
    } 
};