Recent

Author Topic: Some questions about Classes (constructor/destructor/Virtual) [SOLVED]  (Read 1310 times)

Hartmut

  • Hero Member
  • *****
  • Posts: 739
My "knowledge" about objects and classes is old (from Turbo Pascal 5 and 6) and rusty. I've forgotten a lot. Now I face the following problem: I have a self-written class (a dynamic Form, inherited from 'TForm', with a TMemo and some TButtons) which until now did not have any Virtual methods. But now I need a Child-Class, which replaces one method virtually.

Question 1:
Do I need an own constructor in my Child-Class? Until now my class does not have one. I remember very far, that all classes with Virtual Methods need a constructor... Or is it enough to write:
Code: Pascal  [Select][+][-]
  1. MyChildForm:=TMyChildForm.CreateNew(parent)
and this will call the constructor of 'TForm' and everything is fine?

Question 2:
Do I need an own destructor? Until now my class does not have one. What are the rules in which case an own destructor is neccessary?

Question 3+4:
In which case must I call my own destructor (if I need one)? Is it allowed to call the destructor from a method of the same class?

Please be not too short in your answers, because it want to understand how that stuff works. Thanks a lot in advance.
« Last Edit: August 11, 2022, 09:50:58 am by Hartmut »

jollytall

  • Sr. Member
  • ****
  • Posts: 303
Re: Some questions about Classes (constructor/destructor/Virtual)
« Reply #1 on: August 09, 2022, 07:51:30 pm »
AFAIK

1: You must call the constructor of the class to create the Virtual Method Table, but it can be an inherited one, you do not need a separate one. Since in Pascal you can name the constructor the way you want, it is not an issue (unlike C++ where the constructor has the name of the class and hence you need one for your own class type).
2: In general you do not need it. Still if there are any newly introduced elements (i.e. not from an ancestor) of the class that need to be freed up, then you need one, as a local pointer variable (including a non-pointer looking variable holding a class instance) holding any memory is not freed automatically. Make sure, if you have a descendant destructor, call from it the inherited destructor as well, something like:
Code: Pascal  [Select][+][-]
  1. destructor TMyChildForm.Destruct;
  2.   begin
  3.   // do what you want
  4.   inherited Destroy;
  5.   end;
  6.  
3: It is not a good practice to call the destructor at all. Call Free instead. Free is a class method and it checks that the object pointer is not nil, and only then calls Destroy. This can prevent lots of crashes. Be also aware that MyChildForm.Free does not nil the MyChildForm variable holding the class instance (a sort-of pointer). So if you call Free twice you can have a problem. If that risk is valid then call FreeAndNil(MyChildForm) instead.
4: Theoretically you can call the destructor even from a method of the same class, but again, it is better never to call the destructor directly at all. Also make sure that you do not use anything freed in Destroy after you called it. It can be tricky, so be careful, but you can do it.

There is a long write-up about the way objects, classes and alike work under https://github.com/zsoltszakaly/OOPstructuresinpascal, might worth reading.

MarkMLl

  • Hero Member
  • *****
  • Posts: 6647
Re: Some questions about Classes (constructor/destructor/Virtual)
« Reply #2 on: August 09, 2022, 10:48:50 pm »
I'm uncomfortable and hesitant about commenting on this since components are not my strong suit, but suggest that you might be better off with a TFrame for this sort of thing: I've used them a fair amount to populate tabsheets dynamically. You'll find that they "just work" provided that you're careful to edit frame properties in the frame design, not where it is used.

I'm uncertain though about the situation when subclassing a visual component like this. Allowing that the Lazarus IDE and LCL favour using a frame rather than subclassing a form, it /might/ be that a frame-containing-a-frame works...

MarkMLl


MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

PascalDragon

  • Hero Member
  • *****
  • Posts: 5444
  • Compiler Developer
Re: Some questions about Classes (constructor/destructor/Virtual)
« Reply #3 on: August 10, 2022, 09:04:28 am »
Question 1:
Do I need an own constructor in my Child-Class? Until now my class does not have one. I remember very far, that all classes with Virtual Methods need a constructor... Or is it enough to write:
Code: Pascal  [Select][+][-]
  1. MyChildForm:=TMyChildForm.CreateNew(parent)
and this will call the constructor of 'TForm' and everything is fine?

The requirement for a constructor if you want to use virtual methods only exists for TP-style objects. Delphi-style classes don't have that restriction and you can use virtual methods as you like.

And yes, calling TMyChildForm.CreateNew with CreateNew being provided by a parent class is enough to instantiate the correct type.

Question 2:
Do I need an own destructor? Until now my class does not have one. What are the rules in which case an own destructor is neccessary?

You only need your own destructor if you need to free things that you allocated during the lifetime of the class that aren't freed otherwise. E.g. if you create a child control in the constructor you usually pass Self as the Owner parameter, then you don't need to free it manually, but if you allocate something that does not have that Owner concept (e.g. a TStringList) then you need to clean it up yourself.

Question 3+4:
In which case must I call my own destructor (if I need one)? Is it allowed to call the destructor from a method of the same class?

The destructor needs to be called when you no longer need to use the class instance, because this will also release the memory of the class instance. You usually do this by calling Free on your class. This can be done from within the class itself however then you need to take great care that you don't access any fields of the class afterwards as the class instance will no longer be valid once that method returns. Better to free it from outside, e.g. from whatever class you called CreateNew from.

Hartmut

  • Hero Member
  • *****
  • Posts: 739
Re: Some questions about Classes (constructor/destructor/Virtual)
« Reply #4 on: August 10, 2022, 04:04:00 pm »
Thank you MarkMLl for your post. I did not know 'TFrame' and will dive deeper into it, but not for this project, because my class and my program are nearly finished and I don't want to set everything upside down ;-)

MarkMLl

  • Hero Member
  • *****
  • Posts: 6647
Re: Some questions about Classes (constructor/destructor/Virtual)
« Reply #5 on: August 10, 2022, 04:08:12 pm »
Thank you MarkMLl for your post. I did not know 'TFrame' and will dive deeper into it, but not for this project, because my class and my program are nearly finished and I don't want to set everything upside down ;-)

It's very useful, subject to the property-editing caveat. Get that wrong and you are likely to have to open the .lfm in text mode to fix it.

As always, take note of anything PascalDragon says :-)

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

Hartmut

  • Hero Member
  • *****
  • Posts: 739
Re: Some questions about Classes (constructor/destructor/Virtual)
« Reply #6 on: August 10, 2022, 04:10:00 pm »
Thank you very much jollytall and PascalDragon for your detailed and precise answers. Now I see clearer.
I downloaded the document from https://github.com/zsoltszakaly/OOPstructuresinpascal and it looks very interesting. I will read it in the next time. Thanks again.

Meanwhile I got a new question about Classes:
Guess I have a procedure which takes a class variable as a parameter and changes things in the class. Normally I would write something like:

Code: Pascal  [Select][+][-]
  1. procedure set_width_and_height(var MyClass: TMyClass);
  2.    begin
  3.    ...
  4.    end;

But now I want to be able to use this procedure also for all Childs of 'TMyClass'. This does not compile with the 'var' parameter. My question is: is it allowed, to skip the 'var' in this case? Because 'MyClass' is a pointer and it's properties can be changed also without 'var'. It seems to work on the 1st view, but I'm unsure to rely on it.

MarkMLl

  • Hero Member
  • *****
  • Posts: 6647
Re: Some questions about Classes (constructor/destructor/Virtual)
« Reply #7 on: August 10, 2022, 04:21:53 pm »
Guess I have a procedure which takes a class variable as a parameter and changes things in the class.

Make it into a public method of the class being modified, and call it as someInstance.set_width_and_height(...)

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

HeavyUser

  • Sr. Member
  • ****
  • Posts: 397
Re: Some questions about Classes (constructor/destructor/Virtual)
« Reply #8 on: August 10, 2022, 05:30:12 pm »
My question is: is it allowed, to skip the 'var' in this case?
Yes, you can even make it a const if that's what you want.

Because 'MyClass' is a pointer and it's properties can be changed also without 'var'. It seems to work on the 1st view, but I'm unsure to rely on it.
Exactly, you pass a pointer to an instance of the class which you can use to change as you wish. var, const etc protect the pointer value not the class.

PascalDragon

  • Hero Member
  • *****
  • Posts: 5444
  • Compiler Developer
Re: Some questions about Classes (constructor/destructor/Virtual)
« Reply #9 on: August 11, 2022, 09:07:08 am »
Meanwhile I got a new question about Classes:
Guess I have a procedure which takes a class variable as a parameter and changes things in the class. Normally I would write something like:

Code: Pascal  [Select][+][-]
  1. procedure set_width_and_height(var MyClass: TMyClass);
  2.    begin
  3.    ...
  4.    end;

But now I want to be able to use this procedure also for all Childs of 'TMyClass'. This does not compile with the 'var' parameter. My question is: is it allowed, to skip the 'var' in this case? Because 'MyClass' is a pointer and it's properties can be changed also without 'var'. It seems to work on the 1st view, but I'm unsure to rely on it.

A variable for a class instance is in reality merely a pointer. So whether you use var, const or nothing for passing it doesn't change whether you can modify any properties. It only controls whether you can change the class instance itself:

Code: Pascal  [Select][+][-]
  1. procedure Test1(aArg: TObject);
  2. begin
  3.   aArg := TObject.Create;
  4. end;
  5.  
  6. procedure Test2(var aArg: TObject);
  7. begin
  8.   aArg := TObject.Create;
  9. end;
  10.  
  11. var
  12.   o: TObject;
  13. begin
  14.   o := TObject.Create;
  15.   Test1(o); // o will stay the same and the instance created leaks
  16.   Test2(o); // o now changes and the old o leaks
  17.   o.Free; // frees the instance created by Test2
  18. end.

Guess I have a procedure which takes a class variable as a parameter and changes things in the class.

Also as MarkMLI already said if you have something that changes things in a class it normally belongs in that class as a separate method (or a class helper, but let's ignore that can of worms for now :P ).

Hartmut

  • Hero Member
  • *****
  • Posts: 739
Re: Some questions about Classes (constructor/destructor/Virtual)
« Reply #10 on: August 11, 2022, 09:50:38 am »
Thanks a lot to HeavyUser, PascalDragon and MarkMLl for your new posts. I have good answers for my last question. This Topic can be closed.

MarkMLl

  • Hero Member
  • *****
  • Posts: 6647
Re: Some questions about Classes (constructor/destructor/Virtual)
« Reply #11 on: August 11, 2022, 10:16:32 am »
Also as MarkMLI already said if you have something that changes things in a class it normally belongs in that class as a separate method (or a class helper, but let's ignore that can of worms for now :P ).

I think a point to be made there is that a derivative of TForm created by the IDE can have methods added manually.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

 

TinyPortal © 2005-2018