-3

I have multiple descendent classes sharing an ancestor. When I want to destroy an object I don't know what the actual type is, because the pointer holding the actual object has an ancestor type.

Thinks of it like you have multiple descendent from TButton, saving all objects in an array of type TButton, now when you want to destroy the objects, calling TButton(ButtonArray[I]).Destroy cause memory leaks, because it didn't call Destroy method of descendent types.

I want an approach to properly destroy descendent classes from the ancestor Destroy method.

SAMPro
  • 1,068
  • 1
  • 15
  • 39
  • 1
    FYI, if the array type is already `TButton` then you don't need to typecast the elements to `TButton`, eg: `ButtonArray[I].Destroy` or better `ButtonArray[I].Free`. Actually, you wouldn't need any typecast anyway, since `Destroy` and `Free` are introduced all the way in `TObject`, which is the ancestor for all classes. – Remy Lebeau Aug 11 '22 at 20:29
  • When you ask question, please provide proper [mcve]. Without it, we have to guess what the is the real issue with your code. – Dalija Prasnikar Aug 12 '22 at 10:48

1 Answers1

12

This problem doesn't exist.

Since the destructor Destroy is a virtual method, the correct one will be chosen automatically at run-time, because Delphi knows the actual class of every object instance, no matter what kind of pointers you have to it in your source code. (Indeed, try ShowMessage(MyObj.ClassName).)

For example, given TFruit, TApple = class(TFruit), and TBanana = class(TFruit) and

var
  a, b: TFruit;
begin
  a := TApple.Create;
  b := TBanana.Create;
  a.Destroy; // calls TApple.Destroy, if properly overridden
  b.Destroy; // calls TBanana.Destroy, if properly overridden
end;

(except that, of course, you never write x.Destroy but x.Free).

So why doesn't this work for you? Well, this is a common mistake:

TChild = class(TParent)
  constructor Create;
  destructor Destroy;
end;

must be

TChild = class(TParent)
  constructor Create;
  destructor Destroy; override; // <-- Add override!
end;

Otherwise you will not override TParent.Destroy, but simply introduce a new destructor with the same name.

Actually, the compiler tries to warn you about this:

[dcc32 Warning] W1010 Method 'Destroy' hides virtual method of base type 'TObject'

or something like that.

Andreas Rejbrand
  • 105,602
  • 8
  • 282
  • 384
  • Another problem might be in not providing a `Destroy` in the first place, thinking that the existing one will do the job. Which it would if you're not adding any fields that need their own memory allocation. And in that case, you wouldn't get the compiler warning. – Philip J. Rayment Aug 11 '22 at 22:07
  • 2
    @PhilipJ.Rayment: The OP showed some of his code in a now-deleted answer, and there the child has `destructor Destroy;` (without `override`). – Andreas Rejbrand Aug 11 '22 at 22:09
  • 2
    Also make sure that the overridden Destroy calls `inherited;` – Gerry Coll Aug 12 '22 at 02:31