2011-07-01 19 views
1

讓我再給予一個例子來說明我的問題:虛擬函數在繼承中表現怪異?

#include <iostream> 

class PC 
{ 
public: 
    PC():Data(0) 
    { 
    } 
    virtual void display() 
    { 
     std::cout<<"The data is :"<<Data<<std::endl; 
    } 
protected: 
    int Data; 
}; 

class SmartPC:private PC 
{ 
public: 
    SmartPC():PC() 
    { 
    } 
    void convert() 
    { 
     PC* temp=static_cast<PC*>(this); 
     temp->display(); 
    } 
    void display() 
    { 
     std::cout<<"The data is (in bb):"<<a<<std::endl; 
    } 
}; 

int main() 
{ 
    SmartPC SmrtPC; 
    PC* miniPC= static_cast<PC*>(&SmrtPC); 
    SmrtPC.convert(); 
} 

據斯科特邁爾斯:static_cast<PC*>(this);將創建SmartPC的溫度基本副本。但temp->display();執行派生類的display()函數。爲什麼?它不應該執行基地的display()的功能,因爲該對象現在完全是SmartPC的基礎的副本?

的另一個問題是,如果我在temp->data;功能convert()添加行,它說 PC::Data是受保護的,但我從派生類範圍即SmartPC訪問它,那麼爲什麼不工作?

任何幫助表示讚賞。

+1

您可以提供一個引用Meyers說的地方嗎?也許你誤解了他。 –

回答

5

根據斯科特邁爾斯:static_cast<PC*>(this);將創建SmartPC的臨時基本副本。但是temp->display();執行了派生類的display()函數爲什麼這樣呢?它應該執行基地的display()的功能,因爲該對象現在完全是SmartPC的基礎的副本。

沒有副本被創建,你只能鑄造指針

由於類是多態的,通過調用在調用的函數的「正確的」版本的指針結果的virtual功能(根據對象,這是SmartPC *動態類型)。

相反,如果display不是virtual,基類的版本將被調用,因爲對於非virtual方法它的指針,以確定哪個版本被稱爲的靜態類型

displayvirtual也即使它不是明確指定SmartPC,當重寫繼承virtual功能virtual限定符暗示)


通知,而不是,如果你做的事:

PC temp(*this); 

您實際上會創建當前對象的副本,「切片」爲對象類型爲PC。這稱爲「對象切片」,由PC的拷貝構造函數執行;大多數情況下這是不受歡迎的行爲(因爲派生類的對象實際上成爲基類的對象,並且多晶現象不像某些人期望的那樣工作)。


的另一個問題是,如果我在convert()功能temp->data;添加一行,它說PC::Data是受保護的,但我從派生類範圍即SmartPC訪問它,那麼爲什麼沒有工作?

在概念上,當您嘗試訪問temp->data你試圖訪問另一個對象的private成員(這並不重要temp實際上是this),所以訪問被拒絕。您的「派生類特權」訪問protected成員只能在this上工作。

1

它不是類的副本,它是對基類對象的引用,因此它的行爲與其他類似。

您無法訪問受保護成員的原因是因爲您使用了私有繼承。

+0

你能解釋一下嗎?你無法訪問受保護成員的原因是因爲你使用了私有繼承**。由於派生類可以訪問其受保護的成員,無論繼承是在類的範圍內是私有的還是公共的。謝謝 –