【问题标题】:Using an inherited list of objects使用继承的对象列表
【发布时间】:2013-12-20 01:35:45
【问题描述】:

我正在尝试创建一个对象结构,其中一个对象包含其他对象的列表。我对这两个都有一个基类,类似于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 函数似乎有问题,但我无法弄清楚。即使我将项目创建为其预期的项目类,它也会被进一步视为基类,并且没有任何继承的成员可访问(导致访问冲突),因为从不调用继承的构造函数。

我在这里忽略了什么/做错了什么?

【问题讨论】:

  • 你可以在你的构造函数中添加 virtual - 特别是如果你正在使用元类
  • 我无法想象你为什么不使用泛型
  • @DavidHeffernan 因为幕后还有很多事情发生,这些事情没有必要或不相关。 TCollection 不使用泛型 :-)
  • 你需要在这里使用泛型。拒绝它是疯狂的。 TCollection 是为 Delphi 1 设计的。当然它不使用泛型。您可以使用泛型摆脱大量代码。您仍然需要虚拟构造函数。您确实需要阅读 Nick 的新书并考虑 Spring 容器。
  • @DavidHeffernan 如果有办法在TList<> 中添加其他专有属性和功能,那么它可能会起作用,但它们与我的问题无关,所以我没有将它们包括在我的问题中.

标签: delphi inheritance


【解决方案1】:

你的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;

【讨论】:

  • 使用元类创建实例时,不能更改构造函数的参数。派生构造函数必须 override 基构造函数。
  • 现在明白了,在离开电脑一段时间后,带着新鲜的头脑回来:-)
【解决方案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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-22
    相关资源
    最近更新 更多