2012-06-17 50 views
37

假設在Visual C++ 2010這樣的場景:重寫非虛方法

#include <iostream> 
#include <conio.h> 

using namespace std; 

class Base 
{ 
public: 
    int b; 
    void Display() 
    { 
     cout<<"Base: Non-virtual display."<<endl; 
    }; 
    virtual void vDisplay() 
    { 
     cout<<"Base: Virtual display."<<endl; 
    }; 
}; 

class Derived : public Base 
{ 
public: 
    int d; 
    void Display() 
    { 
     cout<<"Derived: Non-virtual display."<<endl; 
    }; 
    virtual void vDisplay() 
    { 
     cout<<"Derived: Virtual display."<<endl; 
    }; 
}; 

int main() 
{ 
    Base ba; 
    Derived de; 

    ba.Display(); 
    ba.vDisplay(); 
    de.Display(); 
    de.vDisplay(); 

    _getch(); 
    return 0; 
}; 

從理論上說,這個小應用程序的輸出應該是:

  • 基地:非虛擬顯示。
  • 基礎:虛擬顯示器。
  • 基礎:非虛擬顯示器。
  • 派生:虛擬顯示。

因爲基類的Display方法不是虛方法,所以Derived類不應該能夠覆蓋它。對?

的問題是,當我運行的應用程序,它打印此:

  • 基地:非虛擬顯示。
  • 基礎:虛擬顯示器。
  • 派生:非虛擬顯示。
  • 派生:虛擬顯示。

所以要麼我不明白虛擬方法的概念,或者在Visual C++中發生了一些奇怪的事情。

有人可以幫我解釋一下嗎?

+0

你絕對有__Base:非虛擬顯示器.__當你改變你的行到'de.Base :: Display()'時。 –

回答

50

是的,你有點誤解。

在這種情況下,派生類中相同名稱的方法將隱藏父方法。你會想象,如果不是這種情況,試圖創建一個與基類非虛方法同名的方法應該會引發錯誤。這是允許的,這不是一個問題 - 如果你直接調用方法,你會做的很好。

但是,作爲非虛擬的,不允許使用允許多態的C++方法查找機制。例如,如果您創建了派生類的實例,但通過指向基類的指針調用了「Display」方法,則將調用基類的方法,而對於「vDisplay」,將調用派生方法。

例如,嘗試添加這些行:

Base *b = &ba; 
b->Display(); 
b->vDisplay(); 
b = &de; 
b->Display(); 
b->vDisplay(); 

...,觀察輸出如預期:

基數:非虛顯示器。
基礎:虛擬顯示器。
基礎:非虛擬顯示器。
派生:虛擬顯示。

+0

Hi @ sje397,謝謝你的回覆。 您是否可以通過指向基類的指針來編寫調用方法的示例,如您所述? 謝謝! –

+0

@Leif Lazar:完成。 – sje397

+0

也如我所說,你也可以使用範圍解析語法從派生實例調用(非虛擬)基本方法。 –

3

是你誤會了一點:

純虛函數:

virtual void fun1()=0 - >必須在派生類中重寫

虛函數:

virtual void fun2() - >可以被覆蓋

正常功能:

void fun3() - >不重寫

爲了實現運行時多態性你需要重寫在C++

0

我想這可能是也更好看虛函數它在靜態與動態綁定的上下文中。

如果該方法是非虛擬的(它在C++中已經默認爲不同於Java),那麼該方法在編譯時綁定到它的調用方,這是不可能知道在運行時將指向的實際對象的。所以,變量類型就是'基礎'的重要部分。