Initilizing a static class member that is itself a class

I'm in the early stages of writing a class that has 2 static instances of other classes. its basically a GUI / basic window manager layered on top of the FABGL libraries that actually drive my vga display

class vgaWindow
{
    public:
    vgaWindow();        //generic constructor
    vgaWindow(String wNAME, uint16_t X0, uint16_t Y0, uint16_t X1, uint16_t Y1 ) ;     //simple constructor
    vgaWindow(String wNAME, uint16_t X0, uint16_t Y0, uint16_t X1, uint16_t Y1, Color *FG0, Color *BG0);
    private:
        static uint16_t wIDused;        //keep track of used id's
        static uint16_t dispW, dispH;

        static fabgl::VGAController disp;     //create the display instance
        static fabgl::Canvas cv;         //create canvas to draw on
       
};

so I know how to initialize the ints in the cpp file:

uint16_t vgaWindow::wIDused=0;
uint16_t vgaWindow::dispW=0;
uint16_t vgaWindow::dispH=0;

but I haven't the slightest clue how to init a class level member that is a class. Is it even possible? am I even saying that right?

this is really a c++ question, but in case its relevant, this code will be running on an esp32. Programed with the esspresso arduino core on platformio.

my second question is around static fabgl::Canvas cv;

per the fabgl documentation (and a look at the source code), there is no default(no argument) constructor. creating an instance of Canvas is meant to be done like this:

static fabgl::Canvas cv(&disp)

I added a method to attach the "canvas" to the "controller" as is done in the constructor meant to be used. Am I on the right path with that? I cant get it to compile until I resolve the initialization, so I have no idea.

ps sorry if this is formatted horribly, I cant seem to fix it. Thanks!

Unsure why you would want to do it like that, if this is about having a single, static instance of an object, you should use singletons instead:

//HPP
class MyClass
private:
  static SomeObject singleton;
public:
  static SomeObject getSingleton() {
    if (singleton == null) singleton = new SomeObject();
    return singleton;
  }
}

//CPP
SomeObject MyClass::singleton = null;
...

Please include the code that describes those classes. I done properly, you might not need the scope specifier.

not sure I "want" to do it that way, I'm just not that advanced of a programmer, I have no idea what a singlton is, although I have several tutorials on the subject in my reading queue. Yes the goal is to have a single static class for all instances of my class. If you're saying singleton's are the way to do it, Ill work through those tutorials tonight.

I'm sure exactly what files you might want to see, so here is the whole library:

thank you

If you do not need access to the "disp" and "cv" outside the context of multiple instances of "vgaWindow", you could also do something like this:

//Header
class vgaWindow {
private:
  static fabgl::VGAController disp;
  static fabgl::Canvas cv;
  static int refCount;
public:
  vgaWindow();
  ~vgaWindow();
}

//Source
VGAController fabgl::disp = null;
VGAController fabgl::cv = null;
int fabgl::refCount = 0;

vgaWindow::vgaWindow()
{
  if (vgaWindow::refCount == 0)
  {
    vgaWindow::disp = new VGAController();
    vgaWindow::cv = new Canvas(&vgaWindow::disp);
  }
  vgaWindow::refCount++;
}

vgaWindow::~vgaWindow()
{
  vgaWindow::refCount--;
  if (vgaWindow::refCount == 0)
  {
    delete vgaWindow::disp;
    delete vgaWindow::cv;
  }
}

This will make sure that there will only be one instance of "disp" and "cv" no matter how many instances of "vgaWindow" you may construct and that proper cleanup is handled in the destructor as well.

Code is untested.

1 Like

You can do it with static if you like (compiles, untested):

vgaWindow.h

#ifndef VGA_WINDOW
#define VGA_WINDOW
#include <Arduino.h>
#include <fabgl.h>

class vgaWindow
{
  public:
    vgaWindow();
    vgaWindow(String wNAME, uint16_t X0, uint16_t Y0, uint16_t X1, uint16_t Y1 );
    vgaWindow(String wNAME, uint16_t X0, uint16_t Y0, uint16_t X1, uint16_t Y1, Color *FG0, Color *BG0);

    static void initController();
    
  private:
    static uint16_t wIDused;
    static uint16_t dispW, dispH;

    static fabgl::VGAController disp;
    static fabgl::Canvas cv;
};
#endif

vgaWindow.cpp

#include "vgaWindow.h"

uint16_t vgaWindow::wIDused=0;
uint16_t vgaWindow::dispW=0;
uint16_t vgaWindow::dispH=0;

fabgl::VGAController vgaWindow::disp;
fabgl::Canvas vgaWindow::cv(&disp);

void vgaWindow::initController() {
  disp.begin();
  disp.setResolution(VGA_640x350_70Hz);
}

main.ino:

#include "vgaWindow.h"

void setup() {
  vgaWindow::initController();
}

void loop() {
}
1 Like

You can have a static member function in a class. You can have also static member functions in another class (inheriting from).

Just to bear in mind:
static member functions exist all the time: they are callable even you have not created an object (instance of the class). And the inheritance structure is not considered on static.

static member functions are called from the outside, not on an object. The constructor of for the class (when you create an object), is not called. So, your static is not called.

But it should be possible to call the static member function from the inherited class in your current class: you had to provide the "scope" of the class inherited.
Example:

class X1 {
static StatMember(void);
};

class X2 : public X1 {
static StatMember(void) {
//my stuff and call other static
X1::StatMember();
}

You can call X2::StatMemer().; which "forwards" to X1::StatMember(). But you had to code.
Inheritance and "dynamic" linking is not used on static members. Static members are like plain C-functions, they do not care any inheritance, constructors, destructors etc.
You had to place code when calling other static member functions (but just static in static).
static does not have anything from derivation (inheritance). It will never call another static when not coded to do so.

hey all--apologize for my absence the last 2 days...A neighbor talking me into helping him take down a tree. 6 trees later, here we are.

I've only have a chance to glance over all the responses, but its seems like what I need to do it possible & there are some detail responses on how to do so.

intend to have of a detailed looked at each solution & hopefull try to implement tonight. I'm exhusted, but I really want to try the stuff ya'll suggested.

Thanks very much for the help thus far!

fabgl::VGAController vgaWindow::disp;
fabgl::Canvas vgaWindow::cv(&disp);

I started with gfvalvo's suggestion, as it was the 2 lines of code I was looking for & just couldn't envison. I'm still wraping my head around scoping. I new I needed to link it back to my class, but I could barley guess at the syntax. closest I had was:

vgaWindow::fabgl::Canvas ::cv(&disp);

which is obviously wrong, but with hints of the right ingredients.

funny story:
I think adding those two lines made it work right away. I say think because I noted, 2hours ago, that adding those two lines change my monitor from having no signal, to being black. An exciting improvement that taunted me for hours. I should mention, this test setup is being done on a monitor that had wonky colors to begin with, one of the color channels was donzo.

my test code just made a simple call to draw a simple green rectangle. Can you guess what color channel was bad?!? It had been working the whole time! :man_facepalming: :man_facepalming: :man_facepalming:

thank you for your assistance

I appreciate you sharing that. At one point I had a very vague thought of doing it that way...setting it NULL & then making a new instance. I did find a simpler solution in another response, but I will definitely squirrel this away for later. and I learned a bit just reading through it. thanks.

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.