2013-12-20 3 views
2

하나의 개체가 다른 개체의 목록을 포함하는 개체 구조를 만들려고합니다. 나는이 두 가지의 기본 클래스를 가지고 있는데, 이는 TCollection/TCollectionItem과 비슷하지만 매우 맞춤화 된 구현입니다. 새로운 항목 (TMyListBase.New를 통해)을 만들 때상속 된 개체 목록 사용

문제가있다 (오타가있는 경우 의사 코드, 죄송합니다)

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; 

개체가 성공적으로 생성되지만 상속 및 모든 필드는 하지 (상속 된 객체의 생성자도 호출되지 않습니다) ...

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