Recent

Author Topic: class abstract  (Read 1266 times)

Dzandaa

  • Hero Member
  • *****
  • Posts: 531
  • From C# to Lazarus
class abstract
« on: March 29, 2026, 12:51:46 pm »
Hi,
I try to use an Abstract class but each descendants have different Create.
Is it possible?

here is part of my code:

Code: Pascal  [Select][+][-]
  1.  
  2. {$mode ObjFPC}{$H+}
  3. {$modeswitch ADVANCEDRECORDS}
  4.  
  5.  
  6. interface
  7.  
  8. uses
  9.  Classes, SysUtils, Generics.Collections,
  10.  Math;
  11.  
  12. // ...
  13.  
  14. THitable = class abstract (TObject)
  15. public
  16.  function Hit(r: TRay; tMin: Double; tMax: Double; rec: HitRecord): Boolean; virtual; abstract;
  17.  constructor Create(); virtual; abstract;
  18. end;  
  19.  
  20. TSphere = class(THitable)
  21.  Private
  22.  _Center: TVec3;
  23.  _Radius: Double;
  24.  _Material: TMaterial;
  25.  constructor Create(VCenter: TVec3; VRadius: Double; VMat: TMaterial); reintroduce;
  26.  function Hit(r: TRay; tMin: Double; tMax: Double; rec: HitRecord): Boolean; reintroduce;
  27.  property Center: TVec3 read _Center write _Center;
  28.  property Radius: Double read _Radius write _Radius;
  29.  property Material: TMaterial read _Material write _Material;
  30. end;                        
  31. //...
  32. implementation    
  33.  
  34. constructor TSphere.Create(VCenter: TVec3; VRadius: Double; VMat: TMaterial);
  35. begin
  36.  Center := VCenter;
  37.  Radius := VRadius;
  38.  Material := VMat;
  39. end;    
  40.  
  41. //...
  42.  
  43. // When I try in my main program:
  44.  
  45. var
  46.  Sphere: TSphere;
  47.  v1: TVec3
  48.  Mat1: TMaterial;
  49.  
  50.  
  51. //...
  52.  
  53.  Sphere := TSphere.Create(v1, 2.0, Mat1); // ---> Error wrong numbers of arguments for Create
  54.  


Any idea to use an abstract class with different create() for descendants?

Thank you.
Regards,
Dzandaa

Thaddy

  • Hero Member
  • *****
  • Posts: 19165
  • Glad to be alive.
Re: class abstract
« Reply #1 on: March 29, 2026, 02:51:36 pm »
I would not even implement a parameterless virtual constructor.
I would implement the constructor(s) in every descendant class
There is already a constructor in any class and that is parameterless too.
The alternative is to add virtual constructors for any numner of and parameter types possible.

Also your use of reintroduce is wrong: that should be override.
« Last Edit: March 29, 2026, 02:53:16 pm by Thaddy »
objects are fine constructs. You can even initialize them with constructors.

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 12345
  • Debugger - SynEdit - and more
    • wiki
Re: class abstract
« Reply #2 on: March 29, 2026, 02:57:16 pm »
Your problem is that you put the constructor private => so it can't be seen.

If you have the problem that a public reintroduced (no sure if need to reintroduce) constructor hides the base class parameter less constructor, then you may need to add "overload;"


Mind, if you call the constructor on the actual class (the class as constant identifier "TSphere") then the virtual constructor is pointless.

A virtual constructor is only needed if you call it on a variable of "type THitAbleClass = class of THitAble;"
A variable of that type could contain any of the descendent class types (not instances, but just the class). And then you need a virtual constructor if you want it to be called / the instance would be of the correct class without virtual constructor)

Dzandaa

  • Hero Member
  • *****
  • Posts: 531
  • From C# to Lazarus
Re: class abstract
« Reply #3 on: March 30, 2026, 09:03:06 pm »
Hi,

Thank you for helping me, I is working now :)

I have another problem, more complicated, but first I continue to find a solution.

B->
Regards,
Dzandaa

mas steindorff

  • Hero Member
  • *****
  • Posts: 583
Re: class abstract
« Reply #4 on: March 31, 2026, 01:34:09 am »
do not forget to add to each new create()
Code: Pascal  [Select][+][-]
  1. inherited create();  // should be the 1st line of your create()
  2. ... work with new parameters after the inherited call ...
  3.  
this calls the the ancestors and eventlly the base class's create which will allocate the base class memory.
Then do the same "inherited" call as the last line in your destroy() as good practice. note: you can leave out the ..create and ..destroy keywords that follow "inherited" if you wish.
 
windows 10 &11, Ubuntu 21+ IDE 3.4 general releases

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 12345
  • Debugger - SynEdit - and more
    • wiki
Re: class abstract
« Reply #5 on: March 31, 2026, 08:15:34 am »
do not forget to add to each new create()
Code: Pascal  [Select][+][-]
  1. inherited create();  // should be the 1st line of your create()
  2. ... work with new parameters after the inherited call ...
  3.  
this calls the the ancestors and eventlly the base class's create which will allocate the base class memory.
Then do the same "inherited" call as the last line in your destroy() as good practice. note: you can leave out the ..create and ..destroy keywords that follow "inherited" if you wish.
 

His base class has an abstract create. So, no, this can't be called.

And it will work without.

The actual mem allocation is done outside the creator. (its in "NewInstance")

The create is for
- triggering NewInstance (magically enforced, no inherited needed)
- initialization.

The 2nd only needs inherited if the inherited create does something (an abstract doesn't do something).

One would normally call inherited, even if it was the empty on in TObject, just because something may later been added to other base classes. But then "abstract" says, nothing will be added.

Dzandaa

  • Hero Member
  • *****
  • Posts: 531
  • From C# to Lazarus
Re: class abstract
« Reply #6 on: March 31, 2026, 11:36:25 am »
Hi,

As I said, I have another problem:

I want a descendant of THitable but this time of create is a Hitable List

In the function Hit, I want to parse the Hitable List and return true if the Ray intersect false otherwise

Code: Pascal  [Select][+][-]
  1.  
  2. THitableList = specialize TobjectList<THitable>;  
  3.  
  4. THitableItems = class(THitable)
  5. private
  6.  _Hitables: THitableList;
  7.  
  8.  public
  9.   constructor Create(HT: THitableList);
  10.   function Hit(r: TRay; tMin: Double; tMax: Double; rec: HitRecord): Boolean;
  11.   destructor Destroy; override;
  12.  public
  13.   property Hitables: THitableList read _Hitables write _Hitables;  
  14. end;
  15.  
  16. constructor THitableItems.Create(HT: THitableList);
  17. var
  18.  t: THitable;
  19. begin
  20.  Hitables := THitableList.Create();
  21.  for t in HT do
  22.   Hitables.Add(t);
  23. // or
  24. // Hitables := HT
  25. // ?
  26. end;  
  27.  
  28. function THitableItems.Hit(r: TRay; tMin: Double; tMax: Double; rec: HitRecord):Boolean;
  29.  var
  30.   hitAnything: boolean;
  31.  ClosestSoFar: Double;
  32.  t: THitable;
  33.  i: Integer;
  34. begin
  35.  hitAnything := false;
  36.  ClosestSoFar := tMax;
  37.  
  38.  for t in Hitables do
  39.  begin
  40.   if(Not T.Hit(r, tMin, ClosestSoFar, rec)) then continue; // I think the problem is here... Because T.Hit is not "linked" with THitableItems
  41.   hitAnything := True;
  42.   ClosestSoFar := rec.T;
  43.  end;
  44.  exit(hitAnything);
  45. end;  
  46.  
  47.  

any idea are welcome :)

But I don't think it's possible in Lazarus.

Thank you.

B->
Regards,
Dzandaa

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 12345
  • Debugger - SynEdit - and more
    • wiki
Re: class abstract
« Reply #7 on: March 31, 2026, 12:08:09 pm »
Well, one think I can see is that "procedure Hit" in THitAbleItems does NOT have "override".

So it does not get triggered, if you have a variable declared as THitAble (never mind what it contains).


 

TinyPortal © 2005-2018