简体   繁体   中英

free super class object from base class delphi

is it possible to free object in super class from base class?

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 will not be used in tbase class(other than freeing)

tsup class var o type is different from tbase cass var o type

is it possible to free tsup.o within tbase.Destroy() ? (so i can void implementing destructor Tsup.Destroy; )

Thanks.

No.

It is not possible that Tbase.Destroy frees Tsup.o .

Tsup inherits the o from Tbase , but because you also gave that same name to the new TStrings field, you can't access the inherited o anymore (except with a pointer or cast trick). In other words: the newly introduced o does not replace the inherited o . . It just hides it.

So both versions of o are present in Tsup , at different offsets in the object, although only one is readily accessible. Tbase only "knows" about its own o , and that is why Tbase.Destroy can't free the TStrings .

You will have to implement ( override ) destructor Destroy in Tsup and do it there. And it should, for good order, call inherited .


The real problem is that the new o does not replace the inherited one. They are at different offsets. When code is compiled, their offset into the object is what the generated code uses to access the member fields, so the base class will always access its own o at its fixed offset and never any other field, even if it has the same name, in a descendant class.

As @Rudy explained, the OOP hierarchy prevents the base class to free a member introduced by descendants.


I guess the gist of the question is how to use an object declared in the base class as a boilerplate for different types of objects in derived classes.

It is possible to make such a construct, where the derived classes creates their own internal object and assigns this object to the base object. That way the base class can handle the destruction. It will be a bit tedious to code all that and may lead to confusion.


Instead, use generics and let the derived classes define any class to the base class object:

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM