2013-10-21 19 views
1
class base 
{ 
public: 
    virtual void showbase() { 
     // ---------- 
    } 
}; 

class base1 { 
public: 
    virtual void showbase1() { 
     // ------- 
    } 
}; 

class derived : public base, public base1 
{ 
    void showbase() { 
     // ---- 
    } 

    void showbase1() { 
     // ------- 
    } 
}; 

int main() 
{ 
    base* p = new derived(); 
    p->showbase1(); 

    base1* p1 = new derived(); 
    p1->showbase(); 
} 

根據我對虛擬函數的理解,是編譯器用運行時(vtable機制)處理它,那麼爲什麼我得到編譯時錯誤。運行時查詢C++中的多態性

+0

什麼是錯誤? –

+0

錯誤C2039:'showbase1()':不是'base'的成員,錯誤C2039:'showbase()':不是'base1'的成員,我理解這個問題,但是我的查詢爲什麼編譯器沒有處理運行時多態性。 – user2516685

+0

查看更新後的答案re:運行時多態性和多重繼承。 –

回答

1

按我的有關虛擬功能的理解是,編譯器運行時(虛函數表的機制)交易,然後爲什麼我收到編譯時錯誤。

「交易」很含糊,vtables並不神奇;在C++虛擬調度中,允許調用的實際函數成爲覆蓋靜態聲明的虛函數的函數。這意味着在編譯時必須知道被覆蓋的函數。

vtable不包含在運行時查找函數所需的信息。相反,它基本上只是一個指向重載函數的指針列表。基礎提供了它的虛函數的完整列表,因此,在給定特定基類型的情況下,編譯器在編譯時知道特定函數覆蓋的基類的vtable中的哪些位置;編譯器可以生成直接到vtable中該位置的代碼,獲取指針並調用覆蓋函數。然後,在運行時,當創建派生類型的實際對象時,派生對象的構造函數將填充基類的vtable,以便檢查vtable的任何內容都將獲取指向派生類型函數的指針。

所以你的代碼的問題是你調用的函數showbase()不在編譯器知道你正在訪問的類型的虛函數列表中,base1;由於base1的vtable中沒有這樣的條目,因此編譯器無法知道base1's vtable中的哪個位置獲得指定名爲showbase()的函數覆蓋的指針。

1

你的基類只知道他們自己的成員函數,所以你不能以這種方式使用它。你可以這樣做,而不是:

base* p = new derived(); 
p->showbase(); 

base1* p1 = new derived(); 
p1->showbase1(); 

要獲得關於運行時多態性的問題,它在處理運行時多態性(後期綁定)通過虛函數表,就像你說的。但是對於多重繼承,基本上每個基類都有一個虛表。您不能通過指向其他基類的指針訪問一個基類的vtable。

1

指向派生類的基類指針只能訪問在基類中定義的成員函數。通過它來嘗試訪問派生類中定義的其他函數是非法的。在你的情況base類沒有定義showbase1,因此這是非法的

base* p = new derived(); 
p->showbase1(); //illegal 

但是,你可以這樣做:

p->showbase(); // legal because showbase is a member function of base 

同樣使用base類指針

你不能訪問 showbase1
base1* p1 = new derived(); 
p1->showbase(); //illegal 
p1->showbase1(); //legal 
+0

,我知道,但我的查詢是在虛擬函數編譯器的情況下依賴於vtable因爲p有派生類對象的內容和派生的vtable有條目showbase1,那麼爲什麼我得到編譯時錯誤,什麼我指出我也理解,但想了解編譯器如何編譯虛擬函數。 – user2516685

+0

你誤解了這個概念。在運行時決定是否調用基類或派生類的虛函數版本。基類和基類指針都不知道在其外部定義的任何函數。因此,試圖訪問除基類的成員函數以外的任何其他函數都是編譯時錯誤。 – Kunal

+0

如果派生類提供虛函數的專門化,那麼派生類的版本將在運行時調用,否則將調用基類的版本。 – Kunal

2

要模擬編譯器,請考慮編譯器看到的內容:

class base 
{ 
public: 
    virtual void showbase() { 
     // ---------- 
    } 
}; 

base* p = /*blah blah*/; 
p->showbase1(); 

是的,base是一個多態類。而p確實是指向base的指針。但是因爲p僅指向base,並且重要的是而不是base1(其中showbase1居住),編譯器像這樣解釋上述代碼。很顯然,我意譯:

Here is a class named `base` with a single virtual method called `showbase`. 
Here is a pointer to a `base` object. Call the method named `showbase1` 

,編譯器抱怨:

嗯,對不起,哥們,但base沒有一個叫 showbase1方法。


你問:

[我]瞭解有關虛擬功能與 該編譯器的交易它在運行時。爲什麼我得到編譯時錯誤?

因爲你寫的代碼是無稽之談。這裏基本上是多態如何工作。

  1. 你用虛擬方法定義一個基類。
  2. 您可以定義一個覆蓋這些虛擬方法的派生類。
  3. 編譯器創建一個vtable,將基類中方法的名稱映射到派生類中的實現。
  4. 當您通過指向基類的指針(或ref)調用基類中的方法時,將調用派生類的實現。

但你正在試圖做的是:

  1. 定義一個基類的虛方法。
  2. 定義覆蓋這些虛擬方法的派生類。
  3. 在完全不同的類中調用函數。
+0

+1最佳答案我今天讀到。 – Kunal

0

p'靜態類型 S型基地,因此你只能用它的功能已經definied到基地致電即使在年底,這將是從功能衍生將被調用,因爲普的動態類型是衍生

同樣的事情發生了P1。

也許你的意思是p->showbase();p1->showbase1();