2010-08-31 100 views
29
#include<iostream> 

using namespace std; 
class base 
{ 
public: 
    virtual void add() { 
     cout << "hi"; 
    } 
}; 

class derived : public base 
{ 
private: 
    void add() { 
     cout << "bye"; 
    } 
}; 

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

輸出爲bye爲什麼我可以通過派生對象的基類指針訪問派生的私有成員函數?

我沒有用,這是如何實現的問題。我知道你使用vtables,並且派生的vtable包含新的add()函數的地址。但是,當我試圖在類之外訪問它時,add()是否是私有的,不應該編譯器生成錯誤?不知怎的,這看起來不正確。

+4

覆蓋和訪問說明符是正交概念。 – sbi 2010-08-31 19:28:33

+0

vtables是一個實現細節。 – 2011-05-11 09:24:37

回答

32

add()是唯一的民營的derived,但靜態類型你已經是base* - 這樣的base的訪問限制。
一般來說,你甚至在編譯時甚至不知道指向base的指針的動態類型是什麼,它可能是,例如,根據用戶輸入進行更改。

這是每C++ 03§11.6

的訪問規則的虛擬功能(第11)是由它的聲明來確定和用於功能不受規則稍後覆蓋它。
[...]在調用點使用用於表示成員函數被調用的對象的表達式類型檢查Access。成員函數在其定義的類中的訪問一般是未知的。

+0

+1 - 感謝您對我的回答的澄清評論。 – 2010-08-31 16:17:23

+0

@Georg Fritzsche你能否給我一個從你複製這個鏈接的地方鏈接到C++ 03的鏈接。我谷歌搜索,但沒有找到,想研究C + + – 2014-05-25 17:46:41

+0

@Jai:[「我在哪裏可以找到當前的C或C++標準文檔?」](http://stackoverflow.com/questions/81656/where-do-i-find -the-current-c-or-c-standard-documents) – 2014-06-02 10:35:44

5

要一點點添加到喬治的回答是:

請記住,編譯器無法控制,也無法保證有關派生類的任何信息。例如,我可以將我的類型發佈到一個庫中,並通過一個全新的程序從中得到它。庫編譯器應該如何知道派生可能具有不同的訪問說明符?編譯庫時,派生類型不存在。

爲了支持這一點,編譯器必須在運行時知道訪問說明符,並在嘗試訪問私有成員時拋出異常。

10

訪問修飾符,例如public,privateprotected僅在編譯期間執行。當通過指向基類的指針調用函數時,編譯器不知道指針指向派生類的實例。根據規則,編譯器可以從這個表達式推斷出,這個調用是有效的。

降低派生類中成員的可見性通常是語義錯誤。現代編程語言(如Java和C#)拒絕編譯此類代碼,因爲在基類中可見的成員總是可以通過基指針在派生類中訪問。

+1

+1最佳答案。 – 2011-05-11 09:25:28

相關問題