2013-08-07 59 views
12

我知道C++通過虛擬函數實現運行時多態,並且虛擬關鍵字被繼承,但在派生類中沒有看到使用虛擬關鍵字。在C++中使用虛擬關鍵字

例如在下面的情況下,即使您在派生類中放棄了virtual關鍵字,仍然使用ptr-> method()調用去派生::方法。那麼這個虛擬關鍵字在派生類中做了多少額外的工作?

#include<iostream> 

using namespace std; 

class base 
{ 
public: 
    virtual void method() 
    { 
     std::cout << std::endl << "BASE" << std::endl; 
    } 
}; 

class derived: public base 
{ 
public: 
    virtual void method() 
    { 
     std::cout << std::endl << "DERIVED" << std::endl; 
    } 
}; 

int main() 
{ 
    base* ptr = new derived(); 
    ptr->method(); 
    return 9; 
} 
+0

正如你所看到的,它是多餘的。 – BoBTFish

+0

@ Nbr44你不會回答這個評論嗎 – triclosan

+0

當覆蓋基類中的虛函數時,'virtual'在派生類中被隱含。 C++ 11還引入了「final」關鍵字,它可以防止進一步的派生類重新實現虛函數。 – dunc123

回答

6

什麼都沒有。只是爲了幫助提醒你什麼是虛擬的功能。

8

virtual只在基類聲明中需要。它在派生類(es)中是可選的,在這些情況下可能主要用作提醒。

C++ 11引入了override以使事情更加明確:它明確地標記派生類中的方法是覆蓋基類的方法。

21

如果派生類的方法通過名稱和簽名匹配其中一個基類的虛擬方法,並且匹配方法是虛擬的,則派生類的方法也變爲虛擬。因此,從技術上講,不需要在派生類中標記「虛擬」這樣的方法。然而,在C++ 11之前,它曾經是一個很好的實踐,因爲這對閱讀代碼的人來說是一個很好的暗示(可能很難記住所有基類的虛函數)。

從C++ 11開始,有兩個額外的關鍵字用於在派生類中執行此操作,這有助於提高可讀性和代碼健壯性。他們是「超越」和「最終」。例如,在派生類的方法中放置«override»,可以確保基類的相應方法實際上是虛擬的。 «final»關鍵字的功能與此相同,它可防止該方法被進一步覆蓋。

我也寫了一篇關於這個更真實世界的基本原理和代碼示例,在我的博客,here

希望它有幫助。祝你好運!因爲根據規則,當你駕駛一類具有虛擬功能,當你重寫驅動編譯類虛函數與函數一起隱含分配虛擬關鍵字基類

+1

我喜歡你的博客文章,我可能會開始使用override/final。 – hauron

+0

'final' *特殊標識符*與'override'加上...不同,它只會抑制派生類型中的重寫。雖然如果虛擬函數不覆蓋另一個函數(爲什麼使它變成虛擬函數?),那麼編譯器將不會驗證它是否覆蓋任何函數,因爲您需要將「final」和'override'。也就是說,'override'需要在基礎中有一個覆蓋,'final'意味着在派生類型中不能覆蓋。一個擡起頭,另一個向下。 [ideone]中的基礎測試(http://ideone.com/2xVsFE) –

+0

@DavidRodríguez-dribeas:大衛,除了當你將該功能標記爲「虛擬」時。例如,如果你有一些標記爲«final»的函數,並且沒有虛擬基礎,你將會得到一個錯誤,例如«只有虛擬成員函數可以標記爲'final'» – 2013-08-07 14:18:28

0

虛擬關鍵字在驅動器類可選。所以你不需要明確地分配虛擬關鍵字。但是在多級繼承期間這個關鍵字是必需的。

例子:

在你的代碼中,我們添加以下代碼。

class derived: public base { 
    public: 
     virtual void method() { // In this line virtual keyword is optional. 
       std::cout << std::endl << "DERIVED :: method function" << std::endl; 
     } 

     virtual void display() { 
       std::cout << std::endl << "DERIVED :: display function" << std::endl; 
     } 
    }; 

    class deriveChild: public derived { 
     public: 
      void method() { 
       std::cout << std::endl << "DERIVECHILD :: method" << std::endl; 
      } 

     void display() { 
       std::cout << std::endl << "DERIVECHILD:: display" << std::endl; 
      } 
    }; 

在main(),如果你使用下面的代碼,它會給你不同的輸出。

base *ptr = new deriveChild(); 
    ptr->method(); // will compile and execute 
    ptr->display(); // will generate error because display() is not part of base class. 

現在,如果要使用deriveChild類的display(),則使用此代碼。在派生類中

derived *ptr = new deriveChild(); 
    ptr->method(); // Compile and Execute 
    ptr->display(); // Compile and Execute 
0

隱式的虛方法在派生類虛擬的,沒有必要virtual.If聲明這將是多餘的聲明明確定義它們。

ptr->method(); 

當編譯器跨越上述聲明

來到 - >將嘗試解決上述聲明,作爲方法()函數是虛擬的,編譯器推遲這一呼籲的解決運行時間。

- >當您在運行時創建派生類的對象時,現在編譯器會知道該方法是派生類。

這個虛擬關鍵字在派生類中做了些什麼?

考慮這種情況下還有一個派生類Derived2 inherting form派生,它有它自己的虛擬方法。

class derived2: public derived 
{ 
public: 
    virtual void method() 
    { 
     std::cout << std::endl << "DERIVED2" << std::endl; 
    } 
}; 

如果你調用主方法()如下面

int main() 
{ 
    base* ptr = new derived2(); 
    ptr->method(); //derived2 class method() will get called 
    return 9; 
} 

如果Derived2的()的方法並不完全是虛擬的,你最終將調用方法考覈的衍生版本() ,失去了運行時多態性的好處。

因此,C++的作者在這裏做了很棒的工作,通過使虛擬關鍵字繼承分層。