2011-05-11 155 views
8

可能重複:
Why can i access a derived private member function via a base class pointer to a derived object?訪問從基類指針派生的私有成員函數派生類對象

#include <iostream> 
using namespace std; 

class B { 
public: 
    virtual void fn1(void) {cout << "class B : fn one \n"; } 
    virtual void fn2(void) {cout << "class B : fn two \n"; } 
}; 

class D: public B { 
    void fn1(void) {cout << "class D : fn one \n"; } 
private: 
    void fn2(void) {cout << "class D : fn two \n"; } 
}; 

int main(void) 
{ 
    B *p = new D; 

    p->fn1(); 
    p->fn2(); 
} 

爲什麼p->fn2()調用派生類的功能,即使fn2D私有?

+1

C++中的第11.6節99。 D中的fn1默認是私有的,因爲沒有指定。 – ColWhi 2011-05-11 09:19:18

+0

@Georg:垃圾問題標題如何幫助打破堆棧溢出的有趣例子。這個問題的標題很棒。 – 2011-05-11 09:20:39

+0

@Sasquiha:C99 ?! – 2011-05-11 09:20:55

回答

5

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

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

0

調用p->fn2()根據p指向的對象的類型在運行時進行評估。在編譯時,編譯將p->fn2()調用看作B::fn2()的調用,並且因爲B::fn2()是公共的,編譯器不會報告唯一的錯誤。僅在運行時纔會對實際函數調用D::fn2()進行評估。

這不會破壞Encapsulation原理,這是C++的稱爲Run-time PolymorphismDynamic Polymorphism

+2

呃..確實如此。 – 2011-05-11 09:21:38

-2

特徵從wikipedia

在OOP當派生類繼承的 基類,的一個目的派生的類可以被稱爲(或強制)爲 ,其或者是基類類型或者是派生類類型的 。如果有 基類方法被 派生類覆蓋,則方法調用 的行爲是不明確的。

虛擬和 之間的區別非虛擬解決了這種不明確性。 如果在基類 中指定的虛擬函數是 ,則派生類的函數 將被調用(如果存在)。如果 不是虛擬的,則將調用基類的 函數。

HTH。

+1

這不回答OP關於訪問修飾符的問題。 – Aamir 2011-05-11 09:16:15

+0

而我們不會在SO上寫簽名。 – 2011-05-11 09:22:15

0

當您執行p = new D時,p->__vfptr現在指向D的虛擬功能表的開始。由於這發生在運行時,因此訪問說明符不起作用。

+1

虛擬功能表是一個實現細節。 – 2011-05-11 09:21:25

+0

'vptr'&'vtbl'是編譯器的實現細節,所以對它們的解釋並不是最好的方法。 – 2011-05-11 09:30:05

相關問題