如果你運行這個程序,你就會發現d2為null。雖然 Derived是從BaseType派生的,但從BaseType類繼承的Clone()函數並不能正確的 支持Derived類:它只拷貝了基類。BaseType.Clone()創建的是一個BaseType對 象,不是派生的Derived對象。這就是為什麼程序中的d2為null而不是派生的 Derived對象。即使你克服了這個問題,BaseType.Clone()也不能正確的拷貝在 Derived類中定義的_dValues數組。一但你實現了ICloneable, 你就強制要求所 有派生類也必須正確的實現它。實際上,你應該提供一個hook函數,讓所有的派 生類使用你的拷貝實現(參見原則21)。在拷貝時,派生類可以只對值類型成員或 者實現了ICloneable接口的引用類型成員進行拷貝。對於派生類來說這是一個嚴 格的要求。在基類上實現ICloneable接口通常會給派生類添加這樣的負擔,因此 在密封類中應該避免實現ICloneable 接口。
因此,當整個繼承結構都必 須實現ICloneable時,你可以創建一個抽象的Clone()方法,然後強制所有的派 生類都實現它。
在這種情況下,你需要定義一個方法讓派生類來創建基 類成員的拷貝。可以通過定義一個受保護的構造函數來實現:
class BaseType
{
private string _label;
private int [] _values;
protected BaseType( )
{
_label = "class name";
_values = new int [ 10 ];
}
// Used by devived values to clone
protected BaseType( BaseType right )
{
_label = right._label;
_values = right._values.Clone( ) as int[ ] ;
}
}
sealed class Derived : BaseType, ICloneable
{
private double [] _dValues = new double[ 10 ];
public Derived ( )
{
_dValues = new double [ 10 ];
}
// Construct a copy
// using the base class copy ctor
private Derived ( Derived right ) :
base ( right )
{
_dValues = right._dValues.Clone( )
as double[ ];
}
static void Main( string[] args )
{
Derived d = new Derived();
Derived d2 = d.Clone() as Derived;
if ( d2 == null )
Console.WriteLine( "null" );
}
public object Clone()
{
Derived rVal = new Derived( this );
return rVal;
}
}
基類並不實現ICloneable接口; 通過提供一個受保護 的構造函數,讓派生類可以拷貝基類的成員。葉子類,應該都是密封的,必要它 應該實現ICloneable接口。基類不應該強迫所有的派生類都要實現ICloneable接 口,但你應該提供一些必要的方法,以便那些希望實現ICloneable接口的派生類 可以使用。
ICloneable接口有它的用武之地,但相對於它的規則來說, 我們應該避免它。對於值類型,你不應該實現ICloneable接口,應該使用賦值語 句。對於引用類型來說,只有在拷貝確實有必要存在時,才在葉子類上實現對 ICloneable的支持。基類在可能要對ICloneable 進行支持時,應該創建一個受 保護的構造函數。總而言之,我們應該盡量避免使用ICloneable接口。
返回教程目錄