2010-07-17 52 views

回答

5

Pavel Minaev's answer from another discussion:

其他人已經解釋有關MemberwiseClone,但沒有人給它爲什麼被保護的解釋。我會盡力說明理由。

這裏的問題是MemberwiseClone只是盲目地複製狀態。在許多情況下,這是不可取的。例如,該對象可能有一個專用字段,它是對List的引用。一個淺的副本,比如MemberwiseClone會做什麼,會導致新的對象指向同一個列表 - 而這個類可能會被寫入,不會期望該列表與其他人共享。

或者一個對象可以有某種形式的ID字段,在構造函數中生成 - 再一次,當您克隆它時,會得到兩個具有相同ID的對象,這可能會導致方法中出現各種奇怪的失敗,獨特。

或者說您有一個打開套接字或文件流的對象,並存儲對該對象的引用。 MemberwiseClone只會複製引用 - 你可以想象,兩個對象試圖將調用交叉到同一個流不會結束。

簡而言之,對於任意對象,「克隆」不是一個明確定義的操作。成員運算符=在C++中默認爲所有類提供的事實更令人討厭,因爲人們經常忘記它在那裏,並且對於複製沒有意義的類或者是危險的類(而且有驚人的許多這樣的類)。

1

如果MemberwiseClone不存在,除了通過使用Reflection之外,對於任何可繼承的類來說,除了要求每個派生類明確提供一個以外,沒有任何方法支持多態克隆操作。派生類提供克隆操作失敗會導致意外的行爲。例如,假設Vehicle,Car和ToyotaCar提供了明確的克隆方法,但ToyotaCorolla沒有。如果某人有ToyotaCorolla類型的對象並試圖克隆它,則生成的對象將是ToyotaCar。由於存在需要多態克隆的情況,並且要求可克隆類的每個派生類提供明確的支持是不方便的,因此MemberwiseClone是該框架的必要部分。

另一方面,MemberwiseClone也可能是危險的。在對象上執行MemberwiseClone會頻繁產生一個破碎的對象;試圖使用破損對象的任何屬性或方法可能會破壞原始文件。

這太糟糕了微軟沒有更好地定義克隆的良好做法。設計一個多態克隆模式是可能的,不需要繼承類來明確地做任何事情,除非它們添加需要特殊處理的字段,或者除非調用者期望克隆方法的聲明返回類型是派生類。雖然後一種情況經常會成爲一種需求,但未明確實施必要的方法會產生編譯時錯誤,而不是錯誤的運行時行爲。

順便說一句,微軟似乎認爲有關深層克隆和淺層克隆有點混淆。沒有。在一個對象上調用「克隆」應該將對象克隆到任何深度,以獲得其定義的語義。克隆FileCabinet(Of T)應該產生一個新的FileCabinet,就FileCabinet的方法而言,它獨立於原始文件,但它應該與原始文件保持相同的T實例。由於文件櫃的目的是保存T的實例,但不對其做任何事情,克隆內閣不應該暗示克隆內容(但它意味着克隆內閣自己用來保存內容的任何陣列)。

順便說一句,如果我有我的dr drhers,那麼在.NET中會有一個接口,由String和原始類型(以及其他許多元素)實現,稱爲DeepClonableIfMutable。當應用於String或其他基元時,DeepCloneIfMutable方法將簡單地返回原始對象。用戶定義的不可變對象可以實現DeepClonableIfMutableto類似的行爲,而可變對象將深度克隆自己和任何嵌套的DeepClonableIfMutable實例。

2
  • 很多東西沒有意義被克隆;任何會談非託管手柄,例如
  • 大多數對象不需要克隆設施
  • 深拷貝東西正確真的硬,如果你去的幾個簡單的情況外
  • 在許多情況下,還有比盲目克隆
  • 更好的比喻手動添加克隆設施你的類型的需要是十分容易

對我來說,這是一個不費吹灰之力,這應該是不是被默認添加到公共API。

相關問題