是否可以从基类中释放超类中的对象?
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;
对象 o 不会在 tbase 类中使用(释放除外)
tsup 类var o 类型不同于 tbase cass var o 类型
是否可以在 tbase.Destroy()中释放 tsup.o ? (所以我可以取消实现析构函数Tsup.Destroy; )
谢谢。
答案 0 :(得分:3)
否
Tbase.Destroy
不可能释放Tsup.o
。
Tsup
继承了o
的{{1}},但是由于您也为新的Tbase
字段赋予了相同的名称,因此无法访问继承的{{1 }}(除指针或强制转换外)。换句话说:新引入的TStrings
不会替代继承的o
。。它只是隐藏它。
因此o
的两个版本o
都存在于o
中,尽管对象很容易被访问,但它们的偏移量不同。 Tsup
仅“知道”自己的Tbase
,这就是o
不能释放Tbase.Destroy
的原因。
您将必须在TStrings
中实现( override )destructor Destroy
,然后在此处执行。而且应该顺序良好,请致电Tsup
。
真正的问题是新的inherited
不能替换继承的o
。它们的偏移量不同。编译代码时,生成的代码将使用它们在对象中的偏移量来访问成员字段,因此基类将始终以其固定偏移量访问其自己的o
,而永远不会访问任何其他字段,即使它具有
答案 1 :(得分: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.