【问题标题】:free super class object from base class delphi从基类 delphi 中释放超类对象
【发布时间】:2019-02-23 22:34:03
【问题描述】:

是否可以从基类中释放超类中的对象?

interface

type
  Tbase = class(TObject)
  public
    o: TObject;
    constructor Create;
    destructor Destroy; override;
  end;

  Tsup = class(Tbase)//there will be lot more  classes based on Tbase
  public
    o: TStrings;
    constructor Create;
  end;

implementation

procedure main();
var
  a: Tsup;
begin
  a := Tsup.Create;
//
  a.Free;
end;

constructor Tbase.Create;
begin
  inherited;
end;

destructor Tbase.Destroy;
begin
  if o <> nil then
    o.Free;
  inherited;
end;
constructor Tsup.Create;
begin
  inherited;
  o := TStringList.Create;
end;
destructor Tsup.Destroy;
begin
  // let tbase to free  o ?
  inherited;
end;

object o 不会在 tbase 类中使用(除了释放)

tsup class var o type 不同于 tbase cass var o type

是否可以在 tbase.Destroy() 中释放 tsup.o ? (所以我可以避免实现 析构函数 Tsup.Destroy;

谢谢。

【问题讨论】:

    标签: delphi


    【解决方案1】:

    没有。

    Tbase.Destroy 不可能释放 Tsup.o

    TsupTbase 继承 o,但是因为您也为新的 TStrings 字段赋予了相同的名称,所以您无法再访问继承的 o(使用指针或强制转换除外诡计)。换句话说:新引入的o 不会取代继承的o。它只是隐藏它。

    所以o 的两个版本都存在于Tsup 中,在对象中的不同偏移处,尽管只有一个版本易于访问。 Tbase 只“知道”它自己的o,这就是为什么Tbase.Destroy 不能释放TStrings

    您必须在 Tsup 中实现 (override) destructor Destroy 并在那里执行。并且它应该,为了良好的秩序,打电话给inherited


    真正的问题是新的o 并没有取代继承的o。它们处于不同的偏移量。编译代码时,它们在对象中的偏移量是生成的代码用来访问成员字段的位置,因此基类将始终在其固定偏移量处访问其自己的o,而不是任何其他字段,即使它具有相同的名称,在后代类中。

    【讨论】:

      【解决方案2】:

      正如@Rudy 解释的那样,OOP 层次结构阻止基类释放后代引入的成员。


      我想问题的要点是如何将基类中声明的对象用作派生类中不同类型对象的样板。

      可以进行这样的构造,派生类创建自己的内部对象并将该对象分配给基对象。这样基类就可以处理破坏。编写所有这些代码会有点乏味,并且可能会导致混乱。


      相反,使用泛型并让派生类为基类对象定义任何类:

      program TestGenerics;
      {$APPTYPE CONSOLE}
      
      uses Classes;
      
      type
        Tbase<T:Class> = class(TObject)  // Constrained to classes
        public
          o: T;  // Used by all derived classes. 
          constructor Create;
          destructor Destroy; override;
        end;
      
        Tsup<T:Class> = class(Tbase<T>) //there will be lot more classes based on Tbase<T>
        public
          constructor Create;
        end;
      
      constructor Tbase<T>.Create;
      begin
        Inherited;
      end;
      
      destructor Tbase<T>.Destroy;
      begin
        o.Free;
        inherited;
      end;
      
      constructor Tsup<T>.Create;
      begin
        Inherited;
      end;
      
      var
        sup : Tsup<TStrings>;
      begin
        sup := Tsup<TStrings>.Create;
        try
          sup.o := TStringList.Create;
          sup.o.Add('Hello');
        finally
          sup.Free;
        end;
      end.
      

      【讨论】:

        猜你喜欢
        • 2023-01-01
        • 2015-04-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-02-01
        • 2017-09-13
        相关资源
        最近更新 更多