2011-11-10 168 views
8

我一直是.Net編碼器(不能說我是程序員)2年。有一個問題我多年來無法理解,那就是基類的一個實例如何保存派生類的實例?基類的實例如何保存派生類的實例?

假設我們有兩大類:

class BaseClass 
{ 
    public A propertyA; 
    public B propertyB; 
} 

class DerivedClass :BaseClass 
{ 
    public C propertyC; 

} 

這怎麼可能發生:

BaseClass obj = new DerivedClass() 

我的意思是,中BaseClass內存模型,對新加入的propertyC沒有空間,所以怎麼可能它仍然擁有propertyC的價值?

在另一邊,怎麼會這樣是不可能發生的:

DerivedClass obj = new BaseClass() 

我認爲這是正確的道路,因爲的DerivedClass內存模型擁有所有的BaseClass的,甚至更多的空間。但是這不是真的,爲什麼?

我知道我在問一個非常愚蠢的問題,但有人能給我一個更詳細的答案嗎?從內存或編譯器的角度來看會更好。

+0

這和這個問題完全一樣,對你的問題寫得很好。 http://stackoverflow.com/questions/4937180/a-base-class-pointer-can-point-to-a-derived-class-object-why-is-the-vice-versa – darnir

+0

謝謝大家的優秀答案!我已經得到了點:)謝謝大家!!!〜 – NextStep

回答

5

因爲(並且這個概念經常被誤解),持有指針的變量是獨立於它指向的對象的實際具體類型的類型。

所以,當你寫

BaseClass obj = new DerivedClass() 

,說BaseClass obj上創建編譯器所理解的堅持的東西是,或者派生的參考,從BaseClass堆棧一個新的參考變量部分。

讀取= new DerivedClass()的部分實際上創建DerivedClass類型的新對象,在堆將其存儲,並在存儲器位置時obj指向指針存儲到該對象。堆上的實際對象DerivedClass;這被稱爲具體類型的對象。

變量obj被聲明爲BaseClass類型。這不是一個具體類型,它僅僅是一個變量類型,僅限制了編譯器從存儲的地址到變量指向一個對象,它是不是一個BaseClass或不從類型派生BaseClass

這樣做是爲了保證無論你投入obj變量,不管它是一個具體類型的BaseClassDerivedClass,它將擁有所有的方法,屬性和類型BaseClass的其他成員。它告訴編譯器,obj變量的所有用途應限制爲只使用類BaseClass的那些成員的用途。

4

由於BaseClass是引用類型,obj不是BaseClass對象。它是一個參考到一個BaseClass對象。具體來說,它是對DerivedClassBaseClass部分的引用。

+0

當我瞭解所有其他答案後,我明白了你的觀點:)謝謝。 – NextStep

2

當你這樣說:

BaseClass obj = new DerivedClass() 

你們不是說「創建一個容器來容納這個BaseClass的對象,然後塞進這個大DerivedClass對象進去」。

實際上,您正在創建一個DerivedClass對象,並且它正在一個足夠用於DerivedClass對象的內存空間中創建。 .NET框架從來沒有失去這個事情的蹤跡,這個事情特別是一個DerivedClass,也從來沒有停止過這樣的事情。

但是,當你說選擇使用BaseClass對象變量時,你只是創建了一個引用/指向該對象的指針,它已經被創建,分配和定義以及所有這些,而你的指針只是更多一點模糊。

這就像房間另一邊的那個傢伙是一個紅頭髮的愛爾蘭稍微超重的雞農,他的牙齒不好,名字叫吉米,很迷人,但你只是把他稱爲「那裏」。儘管你的模糊描述是完全準確的,但你描述他的含義並不會改變他或他的任何細節。

+0

這真是一個有趣和容易理解的答案。謝謝!:) – NextStep

+0

+1! – Lazer

0

從另一個用戶jk在Stackoverflow上完全相同的問題上寫下來的答案。

如果我告訴你我有一條狗,你可以放心地假設我有一條狗。

如果我告訴你,我有一隻寵物,你不知道那隻動物是不是狗,它可能是一隻貓,甚至可能是一隻長頸鹿。不知道一些額外的 信息,你不能安全地認爲我有一隻狗。

類似地,派生對象是基類對象(因爲它是子類 類),因此可以由基類指針指向。但基類 類對象不是派生類對象,因此無法將其分配給 派生類指針。

(吱吱您現在聽到的是比喻拉伸)

假設你現在想給我買禮物送給我的寵物。

在第一種情況下,你知道這是一條狗,你可以給我買一條皮帶, 大家都很開心。

在我還沒有告訴你我的寵物是什麼,所以,如果你是 去反正給我買禮物,你要知道我還沒有 告訴你(或只是猜測)信息,第二個場景,你給我買一個皮帶,如果事實證明我真的有一條狗,每個人都很開心。

但是如果我真的有一隻貓那麼我們現在知道你做了一個壞的 假設(投),並有在皮帶的不快樂貓(運行時錯誤)

+0

我也明白你的意思,謝謝:) – NextStep

0

這是可能的,因爲這樣的內存分配給基類和派生類。在派生類中,首先分配基類的實例變量,然後分派派生類的實例變量。當將基類引用變量分配給派生類對象時,它會查看它所期望的基類實例變量以及「額外」派生類實例變量。

相關問題