Create "persistent" object in class constructor

Hi

I have a class “Display”, which includes all the functions to create my content. To output this on the real display I have another class “SSD1306”, which I need to use in almost every function of “Display”. I would like to create my “SSD1306” object in the constructor of “Display”, but with a scope of the whole “Display” class because I want to create the object just once.

The constructor of “SSD1306” has 3 int as input arguments. I was thinking about just creating the class object in my header file. But this does not work. So how can I create my class object correctly?

SSD1306Wire oled(0x3c, 27, 33); //SDA pin 27, SCL pin 33

Thanks for your help!

Lacking...much

I try to clarify. I'm using "ESP8266 and ESP32 Oled Driver for SSD1306 display 4.0.0" in Eclipse Sloeber.

Display.cpp constructor:

Display::Display()
{
	oled(0x3c, 27, 33); //SDA pin 27, SCL pin 33
	oled.init();
}

Display.h:

class Display
{
public:
	//Constructor:
	Display();

	//Destructor
	virtual ~Display();

private:
	SSD1306Wire oled; //SDA pin 27, SCL pin 33
};

And some parts of the output:

../src/Display.cpp: In constructor 'Display::Display()':
../src/Display.cpp:13:18: error: no matching function for call to 'SSD1306Wire::SSD1306Wire()'
 Display::Display()
/home/student/Arduino/libraries/ESP8266_and_ESP32_Oled_Driver_for_SSD1306_display/src/SSD1306Wire.h:45:5: note: candidate: SSD1306Wire::SSD1306Wire(uint8_t, uint8_t, uint8_t, OLEDDISPLAY_GEOMETRY)
     SSD1306Wire(uint8_t _address, uint8_t _sda, uint8_t _scl, OLEDDISPLAY_GEOMETRY g = GEOMETRY_128_64) {
     ^
/home/student/Arduino/libraries/ESP8266_and_ESP32_Oled_Driver_for_SSD1306_display/src/SSD1306Wire.h:45:5: note:   candidate expects 4 arguments, 0 provided
/home/student/Arduino/libraries/ESP8266_and_ESP32_Oled_Driver_for_SSD1306_display/src/SSD1306Wire.h:37:7: note: candidate: constexpr SSD1306Wire::SSD1306Wire(const SSD1306Wire&)
 class SSD1306Wire : public OLEDDisplay {
       ^
/home/student/Arduino/libraries/ESP8266_and_ESP32_Oled_Driver_for_SSD1306_display/src/SSD1306Wire.h:37:7: note:   candidate expects 1 argument, 0 provided
/home/student/Arduino/libraries/ESP8266_and_ESP32_Oled_Driver_for_SSD1306_display/src/SSD1306Wire.h:37:7: note: candidate: constexpr SSD1306Wire::SSD1306Wire(SSD1306Wire&&)
/home/student/Arduino/libraries/ESP8266_and_ESP32_Oled_Driver_for_SSD1306_display/src/SSD1306Wire.h:37:7: note:   candidate expects 1 argument, 0 provided
../src/Display.cpp:16:19: error: no match for call to '(SSD1306Wire) (int, int, int)'
  oled(0x3c, 27, 33); //SDA pin 27, SCL pin 33

Really don't get what is going on here.

I would recommend looking into C/C++ pointers (I don’t mean tips/tricks/pointers, I mean an actual thing called pointers).

-The gist of it is you would create a variable which is a ‘Pointer to an SSD1306’ inside your display class. In your constructor for Display you need a Pointer to an SSD1306 argument.
-In your program code you create one SSD1306 object.
-Then you create a Display object and pass a Pointer to the SSD1306 object you created to your display object.
-Now you have access to the SSD1306 in your Display class. If you for whatever reason had a bunch of Display class objects created you could just pass them all a pointer to the one SSD1306 object. No need to create an SSD1306 for each Display object.

Barbeerian:
I would recommend looking into C/C++ pointers (I don't mean tips/tricks/pointers, I mean an actual thing called pointers).

If I understand correctly you would create the object outside of the Display class and then pass the pointer to Display?

Edit: I'm also not so sure if working with another Display object around SSD1306 object does make any sense in practice. I got used to always create classes even for simple functions.

Yes you pass the pointer to display. Read up on pointers and you'll see that solution accomplishes what you wanted to do in your original post. It gives you access to the SSD1306 object, which you need to use in almost all the functions of your Display class, in the entire scope of your Display class with only one SSD1306 object being created.

Worked nicely! Thanks for the hint.

Sorry, this is still not solved for me. I realized that for other devices I need to define several classes. And I really do not want to create them all outside of my other class. So how can I properly define a global (class scope) object inside another class as mentioned in my first posts?

If I understang it correctly as an object member initialized via the initialization list of the constructor of the embedding class?

Whandall:
If I understang it correctly as an object member initialized via the initialization list of the constructor of the embedding class?

Or, use inheritance.

Whandall:
If I understang it correctly as an object member initialized via the initialization list of the constructor of the embedding class?

Yes, this is exactly what I mean.

Depends on “I have a display” or “I am a display”.

Whandall:
Depends on "I have a dispay" or "I am a display".

Don't understand this.

I mean I have these SSD1306 class functions like ssd1306.init(), ssd1306.plotPixel(). And then I have my Display class wrapped around which does things like Display.drawCircle(), Display.drawLine(). And of course every of these functions in Display needs to use ssd1306 functions.

And I will never access ssd1306 functions from the outside of Display class.

If you inherit something or emmbed it is more or less a matter of logical structuring.
In both cases you get an object that contains both classes.

I inherit something if I want to be a thing like the inherited, (I am ...)
I embed something if I only want to use such a thing. (I have ...)

VicomtedeValmont:
And I will never access ssd1306 functions from the outside of Display class.

That would be an embedded object then IMHO, a private: base class would work the like.

Ok, a nested class.

class Display
{
public:
 //Constructor:
 Display();

 //Destructor
 virtual ~Connection();


private:
 class SSD1306; //nested class

};

But now I still don't have my object SSD1306 to work with.

The natural approach for me seems like:

class Display
{
public:
	//Constructor:
	Display();

	//Destructor
	virtual ~Display();


private:
	SSD1306 ssd1306;

};
Display::Display():
	ssd1306(pin1, pin2, pin3)
{

}

Whandall:
object member initialized via the initialization list of the constructor of the embedding class

class Display
{
public:
  Display(byte i2caddr, byte i2csda, byte i2cslc) : oled(i2caddr, i2csda, i2cslc) {}
private:
  SSD1306 oled; 
} Display(0x3c, 27, 33);
class SSD1306 {
    byte addr, sda, scl;
  public:
    SSD1306(byte addr, byte sda, byte scl) : addr(addr), sda(sda), scl(scl) {}
    void begin() {
      Serial.print(F("Addr 0x"));
      Serial.print(addr, HEX);
      Serial.print(F(", sda "));
      Serial.print(sda);
      Serial.print(F(", scl "));
      Serial.println(scl);
    }
};
class Display {
  public:
    Display(byte i2caddr, byte i2csda, byte i2cscl) : oled(i2caddr, i2csda, i2cscl) {}
    void begin() {
      oled.begin();
    }
  private:
    SSD1306 oled;
} Display(0x3c, 27, 33);

void setup() {
  Serial.begin(250000);
  Display.begin();
}
void loop() {}
Addr 0x3C, sda 27, scl 33

Perfect! I somehow messed up the initialization list. It works now.

When looking through my code I found a class like the following. I would like to define the class functions outside of the header file. But I do not understand the structure of this class.

class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {

  void onResult(BLEAdvertisedDevice advertisedDevice) {
      Serial.println("onResult");
  } // onResult
}; // MyAdvertisedDeviceCallbacks

VicomtedeValmont:
When looking through my code I found a class like this:
...
But I do not understand the structure of this class.

How come you don't understand the structure of your code?

The base class probably looks like

class BLEAdvertisedDeviceCallbacks {
  virtual void onResult(BLEAdvertisedDevice advertisedDevice) = 0;
};

VicomtedeValmont:
I would like to define the class functions outside of the header file.

Most people define the functions in a cpp file.

void MyAdvertisedDeviceCallbacks::onResult(BLEAdvertisedDevice advertisedDevice) {
  Serial.println("onResult");
}

I just used the pattern from an example to define my callback functions. But I've never seen this

class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks

before. But according to your answer I can just define my member functions of MyAdvertisedDeviceCallbacks as usual without taking the "base class" BLEAdvertisedDeviceCallbacks into account?