Recent

Author Topic: Accessing child class from main form  (Read 3927 times)

nikel

  • Full Member
  • ***
  • Posts: 227
Accessing child class from main form
« on: January 03, 2025, 06:31:55 am »
Hello, I followed the tutorial at this link: https://www.tutorialspoint.com/pascal/pascal_classes.htm

I created this class:
Code: Pascal  [Select][+][-]
  1. unit Answers;
  2.  
  3. {$mode ObjFPC}{$H+}
  4. {$m+}
  5.  
  6. interface
  7.  
  8. uses
  9.   {$IFDEF UNIX}
  10.   CThreads,
  11.   {$ENDIF}
  12.   Classes, SysUtils;
  13.  
  14. type
  15.   TAnswers = class
  16.   protected
  17.     Num           : Byte;
  18.     UserAnswer    : Char;
  19.   public
  20.     constructor Create(N: Byte; U: Char);
  21.  
  22.     procedure SetNum(N: Byte);
  23.     function GetNum(): Byte;
  24.  
  25.     procedure SetUserAnswer(U: Char);
  26.     function GetUserAnswer(): Char;
  27.   end;
  28.  
  29. type
  30.   TCorrectAnswer = class(TAnswers)
  31.   private
  32.     CorrectAnswer    : Char;
  33.   public
  34.     constructor Create(N: Byte); overload;
  35.     constructor Create(N: Byte; C: Char; U: Char); overload;
  36.  
  37.     procedure SetCorrectAnswer(C: Char);
  38.     function GetCorrectAnswer(): Char;
  39.   end;
  40.  
  41. implementation
  42.  
  43. constructor TAnswers.Create(N: Byte; U: Char);
  44. begin
  45.   Num:=N;
  46.   UserAnswer:=U;
  47. end;
  48.  
  49. procedure TAnswers.SetNum(N: Byte);
  50. begin
  51.   Num:=N;
  52. end;
  53.  
  54. function TAnswers.GetNum(): Byte;
  55. begin
  56.   GetNum:=Num;
  57. end;
  58.  
  59. procedure TAnswers.SetUserAnswer(U: Char);
  60. begin
  61.   UserAnswer:=U;
  62. end;
  63.  
  64. function TAnswers.GetUserAnswer(): Char;
  65. begin
  66.   GetUserAnswer:=UserAnswer;
  67. end;
  68.  
  69. constructor TCorrectAnswer.Create(N: Byte);
  70. begin
  71.   inherited Create(N, #0);
  72.   CorrectAnswer:=#0;
  73. end;
  74.  
  75. constructor TCorrectAnswer.Create(N: Byte; C: Char; U: Char);
  76. begin
  77.   inherited Create(N, U);
  78.   CorrectAnswer:=C;
  79. end;
  80.  
  81. procedure TCorrectAnswer.SetCorrectAnswer(C: Char);
  82. begin
  83.   CorrectAnswer:=C;
  84. end;
  85.  
  86. function TCorrectAnswer.GetCorrectAnswer(): Char;
  87. begin
  88.   GetCorrectAnswer:=CorrectAnswer;
  89. end;
  90.  
  91. begin
  92.  
  93. end.

How can I access SetCorrectAnswer and GetCorrectAnswer from my main form?
« Last Edit: January 03, 2025, 07:49:30 am by nikel »

egsuh

  • Hero Member
  • *****
  • Posts: 1524
Re: Accessing child class from main form
« Reply #1 on: January 03, 2025, 09:46:45 am »
The class definition is simply type definition. So, you need a variable that will instantiate the class. So, in your main form,


Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.    Classes, SysUtils, Forms, Controls, Graphics, Dialogs,
  9.    Answers;             // you need to include this unit in the form unit
  10.  
  11. type
  12.    TForm1 = class(TForm)
  13.       Button1: TButton;
  14.       procedure Button1Click(Sender: TObject);
  15.    private
  16.  
  17.    public
  18.  
  19.    end;
  20.  
  21. var
  22.    Form1: TForm1;
  23.    CorrectAnswer: TCorrectAnswer;
  24.  
  25. implementation
  26.  
  27. {$R *.lfm}
  28.  
  29. procedure TForm1.Button1Click(Sender: TObject);
  30. begin
  31.     CorrectAnswer := TCorrectAnswer.create(0);   // instantiate
  32.     try
  33.         CorrectAnswer.SetCorrectAnswer('C');                 // call functions & procedures of CorrectAnswer, not TCorrectAnswer
  34.         ShowMessage(CorrectAnswer.GetCorrectAnswer);
  35.    finally
  36.         CorrectAnswer.Free;
  37.    end;
  38. end;
  39.  
  40. end.
  41.  


And you may define a property like :
Code: Pascal  [Select][+][-]
  1. type
  2.   TCorrectAnswer = class(TAnswers)
  3.   private
  4.     FCorrectAnswer    : Char;   //  This is customary, so as to use CorrectAnswer as a public property
  5.     procedure SetCorrectAnswer(C: Char);
  6.     function GetCorrectAnswer(): Char;
  7.   public
  8.     constructor Create(N: Byte); overload;
  9.     constructor Create(N: Byte; C: Char; U: Char); overload;
  10.  
  11.     property CorrectAnswer : Char read GetCorrectAnswer write SetCorrectAnswer;  
  12.  end;
  13.  
  14. implementation
  15.  
  16. procedure TCorrectAnswer.SetCorrectAnswer(C: Char);
  17. begin
  18.   FCorrectAnswer:=C;
  19. end;
  20.  
  21. function TCorrectAnswer.GetCorrectAnswer: Char;
  22. begin
  23.     Result := FCorrectAnswer;
  24. end;
  25.  
  26.  

And with this definition, you can write in your main form unit:


Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. begin
  3.     CorrectAnswer := TCorrectAnswer.create(0);   // instantiate
  4.     try
  5.         CorrectAnswer.CorrectAnswer := 'C';                 // this will call setCorrectAnswer
  6.         ShowMessage(CorrectAnswer.CorrectAnswer);   // this wil call getCorrectAnswer
  7.    finally
  8.         CorrectAnswer.Free;
  9.    end;
  10. end;






Joanna from IRC

  • Hero Member
  • *****
  • Posts: 1293
Re: Accessing child class from main form
« Reply #2 on: January 03, 2025, 12:21:44 pm »
Another small detail.. it should not be possible to change the value of c Parameter inside of of the procedure SetCorrectAnswer. kodezwerg was nice enough to teach me this back in 2019  thanks kodezwerg  :)
Code: Pascal  [Select][+][-]
  1.   procedure SetCorrectAnswer(Const C: Char);
✨ 🙋🏻‍♀️ More Pascal enthusiasts are needed on IRC .. https://libera.chat/guides/ IRC.LIBERA.CHAT  Ports [6667 plaintext ] or [6697 secure] channel #fpc  #pascal Please private Message me if you have any questions or need assistance. 💁🏻‍♀️

Handoko

  • Hero Member
  • *****
  • Posts: 5386
  • My goal: build my own game engine using Lazarus
Re: Accessing child class from main form
« Reply #3 on: January 04, 2025, 09:53:50 am »
Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. begin
  3.     CorrectAnswer := TCorrectAnswer.create(0);   // instantiate
  4.     try
  5.         CorrectAnswer.CorrectAnswer := 'C';                 // this will call setCorrectAnswer
  6.         ShowMessage(CorrectAnswer.CorrectAnswer);   // this wil call getCorrectAnswer
  7.    finally
  8.         CorrectAnswer.Free;
  9.    end;
  10. end;

I personally think the try-finally block is not needed in the code above. I do not against the usage of exception and try blocks, I know sometimes they are needed. I always avoid using them when there is no good reasons of using them. I read from a game programming article, it said abusing exception block will degenerate the performance.

Any expert here, please explain. Is Try-Finally block really needed in the code above? Should it be removed or not? And why? Please share your thought.

Thaddy

  • Hero Member
  • *****
  • Posts: 16411
  • Censorship about opinions does not belong here.
Re: Accessing child class from main form
« Reply #4 on: January 04, 2025, 10:05:16 am »
You can remove it.
https://wiki.freepascal.org/Avoiding_implicit_try_finally_section
Goes for any managed type.
Implicit exceptions are the default. You should only set them manually if $implicitexceptions are off.
« Last Edit: January 04, 2025, 10:16:36 am by Thaddy »
There is nothing wrong with being blunt. At a minimum it is also honest.

PascalDragon

  • Hero Member
  • *****
  • Posts: 5815
  • Compiler Developer
Re: Accessing child class from main form
« Reply #5 on: January 06, 2025, 11:47:03 am »
Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. begin
  3.     CorrectAnswer := TCorrectAnswer.create(0);   // instantiate
  4.     try
  5.         CorrectAnswer.CorrectAnswer := 'C';                 // this will call setCorrectAnswer
  6.         ShowMessage(CorrectAnswer.CorrectAnswer);   // this wil call getCorrectAnswer
  7.    finally
  8.         CorrectAnswer.Free;
  9.    end;
  10. end;

I personally think the try-finally block is not needed in the code above. I do not against the usage of exception and try blocks, I know sometimes they are needed. I always avoid using them when there is no good reasons of using them. I read from a game programming article, it said abusing exception block will degenerate the performance.

Any expert here, please explain. Is Try-Finally block really needed in the code above? Should it be removed or not? And why? Please share your thought.

If an exception occurs either in the setter of CorrectAnswer the getter of CorrectAnswer or the call of ShowMessage then you'll have a memory leak, because no one will free the CorrectAnswer instance. tryfinally is named a resource protection block for a reason, so use it.

Thaddy

  • Hero Member
  • *****
  • Posts: 16411
  • Censorship about opinions does not belong here.
Re: Accessing child class from main form
« Reply #6 on: January 06, 2025, 04:00:55 pm »
So then why is it documented that inside the routine there is an implicit try/finally? Should we duplicate that anyway?
There is nothing wrong with being blunt. At a minimum it is also honest.

egsuh

  • Hero Member
  • *****
  • Posts: 1524
Re: Accessing child class from main form
« Reply #7 on: January 06, 2025, 04:49:29 pm »
Quote
So then why is it documented that inside the routine there is an implicit try/finally? Should we duplicate that anyway?

The document says we don't have to explicitly finalize AnsiString, Dynamic Array, etc.  So we can omit try and finally in following example, as well as "finalize" itself (thankfully).

var
     arr : array of integer;
begin
     SetLength (arr, 100);
     try
         //  Operations that might raise exceptions
     finally
         Finalize (arr);
     end;
end;
     

We simply write:

var
     arr : array of integer;
begin
     SetLength (arr, 100);
     //  operations that might raise exceptions
end;
     

AFAIK string type seem similars to integer, real, or char type (what are they called?) but in reality it is more like dynamic array in internal operations.
 

BrunoK

  • Hero Member
  • *****
  • Posts: 646
  • Retired programmer
Re: Accessing child class from main form
« Reply #8 on: January 06, 2025, 05:07:40 pm »
Frankly, does one need a try finally on such trivial code ?

PascalDragon

  • Hero Member
  • *****
  • Posts: 5815
  • Compiler Developer
Re: Accessing child class from main form
« Reply #9 on: January 09, 2025, 09:16:44 pm »
So then why is it documented that inside the routine there is an implicit try/finally? Should we duplicate that anyway?

The implicit tryfinally only protects managed variables used inside the function, not manually instantiated object instances, so yes, one needs to duplicate them.

Frankly, does one need a try finally on such trivial code ?

If you can be sure that neither the property getter/setter nor the ShowMessage will raise an exception then (and only then) you can leave out the explicit tryfinally. However even then I would add it nevertheless to be future proof in case these assumption ever change.

 

TinyPortal © 2005-2018