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.