Recent

Author Topic: C++ Constructor translation  (Read 1754 times)

jcdammeyer

  • Full Member
  • ***
  • Posts: 205
  • Embedded System Developer
    • Automation Artisans Inc.
C++ Constructor translation
« on: November 01, 2020, 08:54:08 pm »
I'm taking a stab at converting the Adafruit_GFX library from C++ to FP.  Digging through my "The C++ Programming Language" by Bjarne Stroustrup I can't find a direct reference to this so I'm having trouble figuring out exactly how to convert.  So I thought maybe I'd ask here before I try again with the book.

In C++ we have the public constructor defined in the .h file as WIDTH, HEIGHT protected:
Code: C  [Select][+][-]
  1. public:
  2.   Adafruit_GFX(int16_t w, int16_t h); // Constructor
  3. ...
  4. protected:
  5.   int16_t WIDTH,      ///< This is the 'raw' display width - never changes
  6.       HEIGHT;         ///< This is the 'raw' display height - never changes
  7.  

and then in the cpp file:
Code: C  [Select][+][-]
  1. Adafruit_GFX::Adafruit_GFX(int16_t w, int16_t h) : WIDTH(w), HEIGHT(h) {
  2.   _width = WIDTH;
  3.   _height = HEIGHT;
  4. ...
  5. }
  6.  
Now the pascal translation.
Code: Pascal  [Select][+][-]
  1. protected
  2.   WIDTH : Int16;      ///< This is the 'raw' display width - never changes
  3.   HEIGHT : Int16;     ///< This is the 'raw' display height - never changes
  4.   _width,             ///< Display width as modified by current rotation
  5.   _height,            ///< Display height as modified by current rotation
  6. ...
  7. public
  8.   constructor Adafruit_GFX(w : Int16; h : Int16);
  9.  

and further down
Code: Pascal  [Select][+][-]
  1. constructor TAdafruit_GFX.Adafruit_GFX(w : Int16; h : Int16);
  2. begin
  3.   _width := WIDTH;
  4.   _height := HEIGHT;
  5. ...
  6. end;
  7.  

I could set up WIDTH and HEIGHT as default initializers
Code: Pascal  [Select][+][-]
  1. constructor TAdafruit_GFX.Adafruit_GFX(w : Int16 = WIDTH; h : Int16 = HEIGHT);
  2. end;
  3.  
but then what initializes WIDTH, HEIGHT? 

Inside the Adafruit_SPITFT.cpp the constructor is called:
Adafruit_GFX(w, h) where w,h are arguments to the SPITFT constructor.

Following the constructors AdaFruit_ILI9341 is dependant on Adafruit_SPITFT  which is dependent on Adafruit_GFX and eventually inside Adafruit_ILI9341.h there is passed down to the Adafruit_GFX constructor.

Code: C  [Select][+][-]
  1. #define ILI9341_TFTWIDTH 240  ///< ILI9341 max TFT width
  2. #define ILI9341_TFTHEIGHT 320 ///< ILI9341 max TFT height
  3.  


But that doesn't explain how the protected WIDTH, HEIGHT are initialized.

Or does the  : WIDTH(w), HEIGHT(h)  assign the passed w,h into the protected variables that are then used to initialize the _width and _height?


Hope that description makes sense.
John




jcdammeyer

  • Full Member
  • ***
  • Posts: 205
  • Embedded System Developer
    • Automation Artisans Inc.
Re: C++ Constructor translation
« Reply #1 on: November 02, 2020, 12:53:56 am »
I'm going to reply to my own posting.  After a bit of time reading the C++ specification I have found something called ctor initializers for members of the base class.

So the code fragment
Code: C  [Select][+][-]
  1. Adafruit_GFX::Adafruit_GFX(int16_t w, int16_t h) : WIDTH(w), HEIGHT(h) {
  2.   _width = WIDTH;
  3.   _height = HEIGHT;
  4. ...
  5.  

Assigns the value w into the protected int16_t variable WIDTH and h into protected int16_t variable HEIGHT.  Then inside the constructor those two are used to set two other int16_t variables --  _width, _height;
Code: C  [Select][+][-]
  1. protected:
  2.   void charBounds(char c, int16_t *x, int16_t *y, int16_t *minx, int16_t *miny,
  3.                   int16_t *maxx, int16_t *maxy);
  4.   int16_t WIDTH,      ///< This is the 'raw' display width - never changes
  5.       HEIGHT;         ///< This is the 'raw' display height - never changes
  6.   int16_t _width,     ///< Display width as modified by current rotation
  7.       _height,        ///< Display height as modified by current rotation
  8.       cursor_x,       ///< x location to start print()ing text
  9.       cursor_y;       ///< y location to start print()ing text
  10.  

To me it's not clear why the WIDTH and HEIGHT are initialized in this manner.  Can't see why it couldn't be done this way instead.
Code: C  [Select][+][-]
  1. Adafruit_GFX::Adafruit_GFX(int16_t w, int16_t h)  {
  2.   WIDTH = w; HEIGHT = h;
  3.   _width = WIDTH;
  4.   _height = HEIGHT;
  5. ...
  6.  


So in Pascal I'll do it this way and I honestly can't see why not.  I can see why if the object inherits from some other object that extra parameters might be needed but not in this case.

Code: Pascal  [Select][+][-]
  1. constructor TAdafruit_GFX.Adafruit_GFX(w : Int16; h : Int16);
  2. begin
  3.   WIDTH := w;  HEIGHT := h;
  4.   _width := WIDTH;
  5.   _height := HEIGHT;
  6.   rotation := 0;
  7.   cursor_y := cursor_x := 0;
  8.   textsize_x := textsize_y := 1;
  9.   textcolor := textbgcolor := $FFFF;
  10.   wrap := true;
  11.   _cp437 := false;
  12.   gfxFont := NIL;
  13. end;
  14.  

Is there even a way in FP (or Delphi) to add additional initializers on the constructor definition line?  I don't recall seeing that technique.
John

jamie

  • Hero Member
  • *****
  • Posts: 6130
Re: C++ Constructor translation
« Reply #2 on: November 02, 2020, 01:17:04 am »
I am not sure what you mean by additional initializers ?

you can build the constructor anyway you wish but bare in mind that if you have a parent class you need to call it first..

inherited create(some parameters maybe):

also  normally when creating a class the variables should be zero already..

you should build methods for all of those values instead because each time you change something you may need to write that to the controller.

 for example the cursor location..
etc

SetCursor(x,y);

and in the contructor you use that instead of directly setting the fields..
the fields could be protected so only the method gets to them..
The only true wisdom is knowing you know nothing

jcdammeyer

  • Full Member
  • ***
  • Posts: 205
  • Embedded System Developer
    • Automation Artisans Inc.
Re: C++ Constructor translation
« Reply #3 on: November 02, 2020, 01:30:45 am »
Thanks for the reminder Jamie,

Yes. I've been literally changing the syntax of the Adafruit file as I go and as yet am not close to compiling it.   I have changed the constructor now to be more Object Pascal'ish.  Since the object is defined with TObject I've added the inherited create.   

Code: Pascal  [Select][+][-]
  1. TAdafruit_GFX = class(TObject)
  2. ...
  3. public
  4.   constructor Create(w : Int16; h : Int16);
  5. ...
  6. end;
  7.  
  8. constructor TAdafruit_GFX.Create(w : Int16; h : Int16);
  9. begin
  10.   inherited Create;
  11.   WIDTH := w;  HEIGHT := h;
  12.   _width := WIDTH;
  13.   _height := HEIGHT;
  14.   rotation := 0;
  15.   cursor_y := cursor_x := 0;
  16.   textsize_x := textsize_y := 1;
  17.   textcolor := textbgcolor := $FFFF;
  18.   wrap := true;
  19.   _cp437 := false;
  20.   gfxFont := NIL;
  21. end;
  22.  

BTW, the point to all this is that if I want to talk to Adafruit SPI TFT displays on a Pi or BeagleBone I have to write in C or Python or use some other library that will require who knows what.

So I thought I'd just rewrite the C++ libraries to be Pascal units and then take a stab at a Lazarus application translation of an Arduino program to use the LCD display.

And in conjunction with that, even if the display isn't connected, a TImage object on the main form will show what ends up on the LCD display.  Running a Pi headless with just the LCD shows the information.  Working with the software on the development platform with Screen, keyboard and mouse will still show what is going to be on the display.

That's the intention anyway.
John

jamie

  • Hero Member
  • *****
  • Posts: 6130
Re: C++ Constructor translation
« Reply #4 on: November 02, 2020, 03:41:10 am »
ok,
btw
Fpc does not support that I know of, the daisy chain variable assignments

A := B:= C:= 1;

Nor can it do this

A, B, C := 1;

Too bad too..
oh well

The only true wisdom is knowing you know nothing

jcdammeyer

  • Full Member
  • ***
  • Posts: 205
  • Embedded System Developer
    • Automation Artisans Inc.
Re: C++ Constructor translation
« Reply #5 on: November 02, 2020, 05:20:30 am »
ok,
btw
Fpc does not support that I know of, the daisy chain variable assignments

A := B:= C:= 1;

Nor can it do this

A, B, C := 1;

Too bad too..
oh well

That sucks.  I must admit I'm using Delphi while I'm translating the code since the syntax analyzer is pretty good.  Catches all sorts of things.  Hasn't complained about that.  But then way back Algol-W and Algol-68 (FLACC) didn't have problems with consecutive assignments.  Possibly even UBC Pascal that we used on the Ahmdal-470 didn't have that issue.  But I could be wrong.  I forget lots of things nowadays.

I'm also going to have to write a small parser to convert all the font files or modify the attached program (rewrite in FPC) fontconvert.c to create a Pascal Compatible unit or inc file rather than the .h from true type fonts.

I've attached the gfxfont.pas unit I created from the gfxfont.c/.h files.  Not compiled yet.  There may still be issues.

Baby steps...
John
« Last Edit: November 02, 2020, 05:27:46 am by jcdammeyer »

Zvoni

  • Hero Member
  • *****
  • Posts: 2327
Re: C++ Constructor translation
« Reply #6 on: November 02, 2020, 08:25:27 am »
I'm not a C++-guy (by far not), but considering the Notation of WIDTH(w) and HEIGHT(h),
i wouldn't be surprised, if WIDTH and HEIGHT are actually Macros (#DEFINE's), which unfurl on compile-time.
That said: Both behave more like a Function/nested Function, which
a) if w/h is passed in the constructor use that to initialize the fields
b) otherwise grab some constant (as you found out) and initialize the fields with that value.
One System to rule them all, One Code to find them,
One IDE to bring them all, and to the Framework bind them,
in the Land of Redmond, where the Windows lie
---------------------------------------------------------------------
Code is like a joke: If you have to explain it, it's bad

PascalDragon

  • Hero Member
  • *****
  • Posts: 5481
  • Compiler Developer
Re: C++ Constructor translation
« Reply #7 on: November 02, 2020, 09:38:56 am »
To me it's not clear why the WIDTH and HEIGHT are initialized in this manner.

In my opinion initializers provide clarity, just like Pascal's variable declaration: I know right away what is just plain initialization stuff and what is the more beefy part of the constructor. Also it might be more efficient in case more complex objects are involved in the initialization.

I personally would have even written it like this:

Code: C  [Select][+][-]
  1. Adafruit_GFX::Adafruit_GFX(int16_t w, int16_t h)
  2.   : WIDTH(w)
  3.   , HEIGHT(h)
  4.   , _width(w)
  5.   , _height(h)
  6.      {
  7. ...
  8.  

So in Pascal I'll do it this way and I honestly can't see why not.  I can see why if the object inherits from some other object that extra parameters might be needed but not in this case.

That is indeed the correct translation of this to Object Pascal.

Is there even a way in FP (or Delphi) to add additional initializers on the constructor definition line?  I don't recall seeing that technique.

No, there is not.

jcdammeyer

  • Full Member
  • ***
  • Posts: 205
  • Embedded System Developer
    • Automation Artisans Inc.
Re: C++ Constructor translation
« Reply #8 on: November 02, 2020, 09:50:49 am »
Hi Zvoni,
As I mentioned in an earlier post.  Both WIDTH and HEIGHT are declared inside the class as int16_t.  Also Bjarne Stroustup's book does have one example where the name of the variable is used as if it were a function in the class constructor definition.  So WIDTH(w) appears to be equivalent to WIDTH = w; in C.

I don't believe it was needed in the Adafruit program in the way the code is designed.  It may be a holdover from the way things were done during initial develop and then never cleaned up.  Just because you can doesn't mean you should.

The book explains it well enough for me to determine it's not needed for the Pascal version.  The Adafruit code is set up to give the impression, by use of capitals, that WIDTH and HEIGHT are like #defined constants.  They aren't really.  They are just the application defined values of the width and height.  Like a 320x240 pixel LCD display.  When the constructors are called these two values are written to these variables.

Now if the code needs to rotate the screen into say portrait mode of 240x320 then the _width and _height variables are changed but the original design values of 320x240 for WIDTHxHEIGHT remain the same.  To a C programmer they read like constants.  For Pascal programmers where, like humans, the upper/lower case doesn't change comprehension the all caps just isn't a big deal
John

jcdammeyer

  • Full Member
  • ***
  • Posts: 205
  • Embedded System Developer
    • Automation Artisans Inc.
Re: C++ Constructor translation
« Reply #9 on: November 02, 2020, 09:52:57 am »

That is indeed the correct translation of this to Object Pascal.

Is there even a way in FP (or Delphi) to add additional initializers on the constructor definition line?  I don't recall seeing that technique.

No, there is not.

Thanks for your feedback. 
John

 

TinyPortal © 2005-2018