2013-12-20 109 views
2

我想創建一個對象結構,其中一個對象包含其他對象的列表。我有這兩個基類,類似於TCollection/TCollectionItem,但一個非常自定義的實現。使用繼承的對象列表

type 
    TMyItemBase = class; 
    TMyListBase = class; 

    TMyItemBaseClass = class of TMyItemBase; 

    TMyItemBase = class(TObject) 
    private 
    FOwner: TMyListBase; 
    public 
    constructor Create(AOwner: TMyListBase); 
    destructor Destroy; override; 
    property Owner: TMyListBase read FOwner; 
    end; 

    TMyListBase = class(TMyObjectBase) 
    private 
    FItems: TList; 
    FItemClass: TMyItemBaseClass; 
    function New: TMyItemBase; 
    function GetItem(Index: Integer): TMyItemBase; 
    public 
    constructor Create(AOwner: TMyMainObject; const ItemClass: TMyItemBaseClass); 
    destructor Destroy; override; 
    function Count: Integer; 
    procedure Clear; 
    property Items[Index: Integer]: TMyItemBase read GetItem; default; 
    end; 

implementation 

{ TMyItemBase } 

constructor TMyItemBase.Create(AOwner: TMyListBase); 
begin 
    FOwner:= AOwner; 
end; 

destructor TMyItemBase.Destroy; 
begin 

    inherited; 
end; 


{ TMyListBase } 

constructor TMyListBase.Create(AOwner: TMyMainObject; const ItemClass: TMyItemBaseClass); 
begin 
    inherited Create(AOwner); 
    FItems:= TList.Create; 
    FItemClass:= ItemClass; 
end; 

destructor TMyListBase.Destroy; 
begin 
    Clear; 
    FItems.Free; 
    inherited; 
end; 

procedure TMyListBase.Clear; 
begin 
    while FItems.Count > 0 do begin 
    TMyItemBase(FItems[0]).Free; 
    FItems.Delete(0); 
    end; 
end; 

function TMyListBase.Count: Integer; 
begin 
    Result:= FItems.Count; 
end; 

function TMyListBase.GetItem(Index: Integer): TMyItemBase; 
begin 
    Result:= TMyItemBase(FItems[Index]); 
end; 

function TMyListBase.New: TMyItemBase; 
begin 
    Result:= FItemClass.Create(Self); 
    FItems.Add(Result); 
end; 

(僞代碼,對不起,如果有任何錯別字)

問題是,當一個新項目創建(通過TMyListBase.New),對象創建成功,但繼承和所有的字段都沒有(繼承對象的構造是從來沒有所謂的)...

type 
    TMyItem = class; 
    TMyItems = class; 

    TMyItem = class(TMyItemBase) 
    private 
    //various unrelated fields 
    public 
    constructor Create; 
    destructor Destroy; override; 
    //various unrelated properties 
    end; 

    TMyItems = class(TMyListBase) 
    private 
    function GetItem(Index: Integer): TMyItem; 
    function New: TMyItem; 
    public 
    constructor Create(AOwner: TMyMainObject); 
    destructor Destroy; override; 
    property Items[Index: Integer]: TMyItem read GetItem; default; 
    end; 

implementation 

{ TMyItem } 

constructor TMyItem.Create; 
begin 
    inherited; 
    //Initialize some fields 
end; 

destructor TMyItem.Destroy; 
begin 
    //Destroy some fields 
    inherited; 
end; 

{ TMyItems } 

constructor TMyItems.Create(AOwner: TMyMainObject); 
begin 
    inherited Create(AOwner, TMyItem); 

end; 

destructor TMyItems.Destroy; 
begin 

    inherited; 
end; 

function TMyItems.GetItem(Index: Integer): TMyItem; 
begin 
    Result:= TMyItem(inherited Channels[Index]); 
end; 

function TMyItems.New: TMyItem; 
begin 
    Result:= TMyItem(inherited New); 
end; 

這似乎是有點問題New功能,但我不能弄明白。即使我將該項目創建爲其預期的項目類,它將被進一步視爲基類,並且沒有任何繼承的成員可訪問(提供訪問衝突),因爲從不調用繼承的構造函數。

我在這裏忽略/做錯了什麼?

+0

可以添加虛擬到你的構造 - 特別是如果你使用的元類 – Jason

+0

我無法想象,爲什麼你不使用泛型 –

+0

@DavidHeffernan因爲有很多更多的事情這是沒有必要的幕後或相關的包括。 'TCollection'不使用泛型:-) –

回答

6

您的TMyItemBase.Create()構造函數需要聲明爲virtual,然後子類需要override它。這在使用元類型構造對象時很重要。例如:

type 
    TMyItemBase = class(TObject) 
    ... 
    public 
    constructor Create(AOwner: TMyListBase); virtual; 
    ... 
    end; 

constructor TMyItemBase.Create(AOwner: TMyListBase); 
begin 
    inherited Create; 
    FOwner := AOwner; 
end; 

type 
    TMyItem = class(TMyItemBase) 
    ... 
    public 
    constructor Create(AOwner: TMyListBase); override; 
    ... 
    end; 

constructor TMyItem.Create(AOwner: TMyListBase); 
begin 
    inherited Create(AOwner); 
    ... 
end; 
+1

使用元類創建實例時,不能更改構造函數的參數。派生構造函數**必須**覆蓋基類構造函數。 –

+0

現在明白了,離開電腦一段時間後,回來一個新鮮的頭腦:-) –

2

嘗試使用仿製藥!

type 
     TMyItem = class 
     //Implement your class here 
     end; 

    //Use it now! 
    var 
     MyItemsList:TObjectList<TMyItem>; 

    // or implement your generic class customization: 
    type 
     TVeryMyItemsList = class(TObjectList<TMyItem>) 

     end; 
    // Or implement your generic class 
    type 
    TMyGeneric<T> = class(TObjectList<T>) 

    end; 
    //where T is any type