[英]Assigning derived class object to a parent class reference
當我看到時,我總是感到困惑:
Parent ref = new Child();
其中Child類擴展Parent。
ref
如何在內存中看起來像? Child ref = new Child();
對象在內存中的外觀如何?
你的問題不清楚。 有兩個相關的內存位置。 該變量與存儲位置相關聯。 該存儲位置包含對另一個存儲位置的引用 。
變量的存儲位置通常實現為四字節或八字節整數,其中包含“托管指針” - 垃圾收集器已知的內存地址。
對象的內存布局也是CLR的實現細節。 與對象關聯的內存緩沖區將包含對象的所有數據 - 字段的所有值和諸如此類的東西。 它還包含對另一個內存位置的引用,該對象的虛函數表 。
然后,虛函數表(vtable)包含更多引用 ,這次引用引用與最派生類型的對象關聯的方法。
如何處理虛擬方法? 非虛?
通過從變量中查找對象引用,然后查找vtable,然后在vtable中查找方法,然后調用該方法來執行虛方法。
非虛方法不是通過vtable調用的,因為它們在編譯時是已知的。
它與......有什么不同?
在對象上調用的非虛方法將根據變量的類型調用方法的版本。 調用對象的虛方法將根據變量引用的對象的類型調用方法的版本。
如果不是很清楚,您可能需要閱讀我的文章,該文章解釋了如何使用沒有它們的語言“模擬”虛擬方法。 如果你能理解如何自己實現虛擬方法在沒有他們的語言,這將有助於你了解我們如何其實並實現虛擬方法。
ref
是一個Child
對象。 在Child
類上調用虛方法。 但是,僅在Child
類中定義的方法在分配給Parent
對象時不可見。
如果foo()
不是虛擬的,那么編譯將根據變量ref
的聲明類型選擇一個方法。 如果你有Parent ref = new Child();
然后將調用Parent.foo()
。 如果您有Child ref = new Child();
然后將調用Child.foo()
。 當然,在這種情況下,C#編譯器會要求您在Child.foo()
的聲明中使用new
來表示您的意思是隱藏Parent
的實現。
我想ref
只包含可以找到引用的Child
對象的地址。 如果調用虛方法,則調用的實際方法取決於對象的動態類型( Child
); 如果調用非虛方法,則取決於靜態類型( Parent
)。 它與Child ref = ...
不同,因為在那一個中,靜態類型是Child
而不是Parent
。
我希望這不是功課:)
可以這樣想(假設Parent不是抽象類)
Parent ref = new Child();
和
Parent ref = new Parent();
大致相同,除了在Child中重寫的虛擬方法將被調用,而不是后者。
聲明對象的類型將確定可用的方法。 聲明一個對象是一個不像你實例化它的特定類型 - 前一種情況 - 會影響在運行時調用哪些方法,但前提是這些方法被聲明為抽象或虛擬。
在任何一種情況下,假設您在ref上調用了方法foo
。 運行時在類Parent
上很好的方法foo
。 然后,運行時將查看foo
為虛擬(或抽象)。 如果foo
不是虛擬的或抽象的,那么運行時會調用foo
Parent定義然后在那里,並完成它。 但是,如果foo
是虛擬的或抽象的,運行時將檢查ref是否真的被實例化為覆蓋foo
的更具體的類型。 如果是的話,它會調用 foo
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.