Passing a single class instance to another class

Would some one please put me out of my misery. I've been working on this single issue for days and I don't know how to figure it out. I just want to create a single "debug" class that can be shared through out my project. Below is the simplified code to show the issue :

Main.ino

#include "Puzzle.h"

Puzzle puzzle;

void loop(){
  puzzle.loop();
}

void setup(){
  puzzle.setup();
}

Puzzle.h

#ifndef PUZZLE_H
#define PUZZLE_H

#include "Debug.h"
#include "Box.h"

class Puzzle {  
  private:
    Debug _debug;
    Box _box;
  public:
    void setup();
    void loop();
};

#endif

Puzzle.cpp

#include "Puzzle.h"
#include "Box.h"

void Puzzle::setup(){
  _debug = Debug();
  _box = Box(&_debug);

  
  _debug.line("Puzzle Setup");
}

void Puzzle::loop(){
}

Box.h

#ifndef BOX_H
#define BOX_H

#include "Debug.h"

class Box {
  private:
    Debug &_debug;
  public:
    Box(Debug &debug);
};

#endif

Box.cpp

#include "Box.h"
#include <Arduino.h>

Box::Box(Debug &debug) :
 _debug(&debug) {
  pinMode(28, INPUT_PULLUP);
}

Debug.h

#ifndef DEBUG_H
#define DEBUG_H

class Debug {
  private:
    bool _state;
  public:
    Debug();
    void line(const char *str);
    void line(int);
    void newline();
};

#endif

Debug.cpp

#include "Debug.h"
#include <Arduino.h>

Debug::Debug() : _state(false) {
  if (_state == false){
    Serial.begin(9600);
    _state = true;
  }
}
void Debug::line(const char *messageChar) {
  if (_state){
    const char *p;
    p = messageChar;
    while (*p) {
        Serial.print(*p);
        p++;
    }
    newline();
  }
}
void Debug::line(int messageInt) {
  if (_state){
    Serial.print(messageInt);
    newline();
  }
}
void Debug::newline() {
  if (_state){
    Serial.println();
  }
}

Errors

sketch\Puzzle.cpp: In member function 'void Puzzle::setup()':
Puzzle.cpp:6:21: error: no matching function for call to 'Box::Box(Debug*)'
   _box = Box(&_debug);
                     ^
In file included from sketch\Puzzle.h:5:0,
                 from sketch\Puzzle.cpp:1:
sketch\Box.h:10:5: note: candidate: Box::Box(Debug&)
     Box(Debug &debug);
     ^~~
sketch\Box.h:10:5: note:   no known conversion for argument 1 from 'Debug*' to 'Debug&'
sketch\Box.h:6:7: note: candidate: constexpr Box::Box(const Box&)
 class Box {
       ^~~
sketch\Box.h:6:7: note:   no known conversion for argument 1 from 'Debug*' to 'const Box&'
sketch\Box.h:6:7: note: candidate: constexpr Box::Box(Box&&)
sketch\Box.h:6:7: note:   no known conversion for argument 1 from 'Debug*' to 'Box&&'
Main:3:8: error: use of deleted function 'Puzzle::Puzzle()'
 Puzzle puzzle;
        ^~~~~~
In file included from D:\project\escape\puzzle box\source\Main\Main.ino:1:0:
sketch\Puzzle.h:7:7: note: 'Puzzle::Puzzle()' is implicitly deleted because the default definition would be ill-formed:
 class Puzzle {
       ^~~~~~
Puzzle.h:7:7: error: no matching function for call to 'Box::Box()'
In file included from sketch\Puzzle.h:5:0,
                 from D:\project\escape\puzzle box\source\Main\Main.ino:1:
sketch\Box.h:10:5: note: candidate: Box::Box(Debug&)
     Box(Debug &debug);
     ^~~
sketch\Box.h:10:5: note:   candidate expects 1 argument, 0 provided
sketch\Box.h:6:7: note: candidate: constexpr Box::Box(const Box&)
 class Box {
       ^~~
sketch\Box.h:6:7: note:   candidate expects 1 argument, 0 provided
sketch\Box.h:6:7: note: candidate: constexpr Box::Box(Box&&)
sketch\Box.h:6:7: note:   candidate expects 1 argument, 0 provided
sketch\Box.cpp: In constructor 'Box::Box(Debug&)':
Box.cpp:5:9: error: invalid initialization of non-const reference of type 'Debug&' from an rvalue of type 'Debug*'
  _debug(&debug) {
         ^~~~~~
exit status 1
no matching function for call to 'Box::Box(Debug*)'

I've tried every combination of passing values, references and pointers along the entire path. Literally every variation.

I totally get that this is newbie stuff but I have watched hours and hours of youtube videos and read countless articles and can't find any information about how to do what I am attempting how to do. I really would appreciate help on how to get this to work.

I've not read in details but seems the compiler complains that you pass a pointer where it expects a reference

error: no matching function for call to 'Box::Box(Debug*)'

try with

void Puzzle::setup(){
  _debug = Debug();
  _box = Box(_debug);
  _debug.line("Puzzle Setup");
}

When an object contains objects you have to provide any necessary arguments to those object's constructors in the parent constructor. Since you didn't define a constructor for Puzzle there was no way to provide Box with the required constructor argument.

Add this to Puzzle:
public: Puzzle() : _box(_debug) {};

You tried to do it in Puzzle::setup() but by then it was too late. The Box object has to be constructed when the Puzzle is constructed.

Thank you both for your time :

@J-M-L : I tried all combinations of variables, pointers and references. When I did your suggestion the errors are :

sketch\Puzzle.cpp: In member function 'void Puzzle::setup()':
Puzzle.cpp:6:21: error: no matching function for call to 'Box::Box(Debug*)'
   _box = Box(&_debug);
                     ^
In file included from sketch\Puzzle.h:5:0,
                 from sketch\Puzzle.cpp:1:
sketch\Box.h:10:5: note: candidate: Box::Box(Debug&)
     Box(Debug &debug);
     ^~~
sketch\Box.h:10:5: note:   no known conversion for argument 1 from 'Debug*' to 'Debug&'
sketch\Box.h:6:7: note: candidate: constexpr Box::Box(const Box&)
 class Box {
       ^~~
sketch\Box.h:6:7: note:   no known conversion for argument 1 from 'Debug*' to 'const Box&'
sketch\Box.h:6:7: note: candidate: constexpr Box::Box(Box&&)
sketch\Box.h:6:7: note:   no known conversion for argument 1 from 'Debug*' to 'Box&&'
sketch\Box.cpp: In constructor 'Box::Box(Debug&)':
Box.cpp:5:9: error: invalid initialization of non-const reference of type 'Debug&' from an rvalue of type 'Debug*'
  _debug(&debug) {
         ^~~~~~
Main:3:8: error: use of deleted function 'Puzzle::Puzzle()'
 Puzzle puzzle;
        ^~~~~~
In file included from D:\project\escape\puzzle box\source\Main\Main.ino:1:0:
sketch\Puzzle.h:7:7: note: 'Puzzle::Puzzle()' is implicitly deleted because the default definition would be ill-formed:
 class Puzzle {
       ^~~~~~
Puzzle.h:7:7: error: no matching function for call to 'Box::Box()'
In file included from sketch\Puzzle.h:5:0,
                 from D:\project\escape\puzzle box\source\Main\Main.ino:1:
sketch\Box.h:10:5: note: candidate: Box::Box(Debug&)
     Box(Debug &debug);
     ^~~
sketch\Box.h:10:5: note:   candidate expects 1 argument, 0 provided
sketch\Box.h:6:7: note: candidate: constexpr Box::Box(const Box&)
 class Box {
       ^~~
sketch\Box.h:6:7: note:   candidate expects 1 argument, 0 provided
sketch\Box.h:6:7: note: candidate: constexpr Box::Box(Box&&)
sketch\Box.h:6:7: note:   candidate expects 1 argument, 0 provided
exit status 1
no matching function for call to 'Box::Box(Debug*)'

@johnwasser : things are a little more complicated because I also need to initialize _debug as well as _box. I tried a few setups and could not make any progress. For example...

void Puzzle::setup() :
  _debug(Debug()),
  _box(_debug)
{
  _debug.line("Puzzle Setup");
}

Resulted in the following errors :

sketch\Puzzle.cpp: In member function 'void Puzzle::setup()':
Puzzle.cpp:5:3: error: only constructors take member initializers
   _debug(Debug()),
   ^~~~~~
sketch\Box.cpp: In constructor 'Box::Box(Debug&)':
Box.cpp:5:9: error: invalid initialization of non-const reference of type 'Debug&' from an rvalue of type 'Debug*'
  _debug(&debug) {
         ^~~~~~
Main:3:8: error: use of deleted function 'Puzzle::Puzzle()'
 Puzzle puzzle;
        ^~~~~~
In file included from D:\project\escape\puzzle box\source\Main\Main.ino:1:0:
sketch\Puzzle.h:7:7: note: 'Puzzle::Puzzle()' is implicitly deleted because the default definition would be ill-formed:
 class Puzzle {
       ^~~~~~
Puzzle.h:7:7: error: no matching function for call to 'Box::Box()'
In file included from sketch\Puzzle.h:5:0,
                 from D:\project\escape\puzzle box\source\Main\Main.ino:1:
sketch\Box.h:10:5: note: candidate: Box::Box(Debug&)
     Box(Debug &debug);
     ^~~
sketch\Box.h:10:5: note:   candidate expects 1 argument, 0 provided
sketch\Box.h:6:7: note: candidate: constexpr Box::Box(const Box&)
 class Box {
       ^~~
sketch\Box.h:6:7: note:   candidate expects 1 argument, 0 provided
sketch\Box.h:6:7: note: candidate: constexpr Box::Box(Box&&)
sketch\Box.h:6:7: note:   candidate expects 1 argument, 0 provided
exit status 1
only constructors take member initializers

You expect state could something other than false?

That is left over from when I was running the code via an init() method. I will pull it out.

_debug is a reference, not a pointer:

Your constructor expects a reference, not a pointer:

@PieterP : Thanks for your help. I made the changes you requested and it still resulted in errors (at bottom). I will also include all other relevant info (which is probably repeated in first post) to make sure we are in the same page :

Box.h

class Box {
  private:
    Debug &_debug;
  public:
    Box(Debug &debug);
};

Box.cpp

Box::Box(Debug &debug) :
 _debug(debug) {
  pinMode(28, INPUT_PULLUP);
}

Puzzle.h

#include "Debug.h"
#include "Box.h"

class Puzzle {  
  private:
    Debug _debug;
    Box _box;
  public:
    void setup();
    void loop();
};

Puzzle.cpp


void Puzzle::setup(){
  _debug = Debug();
  _box = Box(_debug);
  
  _debug.line("Puzzle Setup");
}

void Puzzle::loop(){
}

Errors

sketch\Puzzle.cpp: In member function 'void Puzzle::setup()':
Puzzle.cpp:6:20: error: use of deleted function 'Box& Box::operator=(Box&&)'
   _box = Box(_debug);
                    ^
In file included from sketch\Puzzle.h:5:0,
                 from sketch\Puzzle.cpp:1:
sketch\Box.h:6:7: note: 'Box& Box::operator=(Box&&)' is implicitly deleted because the default definition would be ill-formed:
 class Box {
       ^~~
Box.h:6:7: error: non-static reference member 'Debug& Box::_debug', can't use default assignment operator
Main:3:8: error: use of deleted function 'Puzzle::Puzzle()'
 Puzzle puzzle;
        ^~~~~~
In file included from D:\project\escape\puzzle box\source\Main\Main.ino:1:0:
sketch\Puzzle.h:7:7: note: 'Puzzle::Puzzle()' is implicitly deleted because the default definition would be ill-formed:
 class Puzzle {
       ^~~~~~
Puzzle.h:7:7: error: no matching function for call to 'Box::Box()'
In file included from sketch\Puzzle.h:5:0,
                 from D:\project\escape\puzzle box\source\Main\Main.ino:1:
sketch\Box.h:10:5: note: candidate: Box::Box(Debug&)
     Box(Debug &debug);
     ^~~
sketch\Box.h:10:5: note:   candidate expects 1 argument, 0 provided
sketch\Box.h:6:7: note: candidate: constexpr Box::Box(const Box&)
 class Box {
       ^~~
sketch\Box.h:6:7: note:   candidate expects 1 argument, 0 provided
sketch\Box.h:6:7: note: candidate: constexpr Box::Box(Box&&)
sketch\Box.h:6:7: note:   candidate expects 1 argument, 0 provided
exit status 1
use of deleted function 'Box& Box::operator=(Box&&)'

I'm guessing this is because _debug and _box need to be defined. I tried to do this prior using the member initialization list and could not get it to work.

Thanks for everyones help

What are you trying to do here? _debug is already initialized, why assign a new instance to it?

Why not just:

class Puzzle {  
  private:
    Debug _debug;
    Box _box { _debug };
  public:
    void setup();
    void loop();
};
void Puzzle::setup(){
  _debug.line("Puzzle Setup");
}

@PieterP : So that is exactly what I was trying to find. Is there a name where I learn more about that "approach" or whatever you want to call it. I have read like 30 articles about OOP with arduino and watched dozens of youtube videos and haven't seen.

I honestly can't tell you how much I appreciate your help.

@PieterP : I'm sorry...I spoke too soon....it compiles but I am not able to use _debug...it doesn't output to serial console any longer

You shouldn't do IO in constructors, constructors of global objects run before the main function and before the hardware is initialized.
It's common practice to do things like this in a begin() method.

I finally got it all to compile without warnings and moved Arduino calls out of constructors:

main.ino:

#include "Puzzle.h"

Puzzle puzzle;

void loop(){
  puzzle.loop();
}

void setup(){
  puzzle.setup();
}

Box.cpp

#include "Box.h"
#include <Arduino.h>

Box::Box(Debug debug) : _debug(debug)
{
}

void Box::begin()
{
  _debug.begin();
  
  pinMode(28, INPUT_PULLUP);
}

Box.h

#ifndef BOX_H
#define BOX_H

#include "Debug.h"

class Box {
  private:
    Debug _debug;
    
  public:
    Box(Debug debug);
    void begin();
};

#endif

Debug.cpp

#include "Debug.h"
#include <Arduino.h>

Debug::Debug() : _state(false)
{
}

void Debug::begin()
{
  if (_state == false)
  {
    Serial.begin(9600);
    _state = true;
  }
}

void Debug::line(const char *messageChar)
{
  if (_state)
  {
    const char *p;
    p = messageChar;
    while (*p)
    {
      Serial.print(*p);
      p++;
    }
    newline();
  }
}
void Debug::line(int messageInt)
{
  if (_state)
  {
    Serial.print(messageInt);
    newline();
  }
}
void Debug::newline()
{
  if (_state)
  {
    Serial.println();
  }
}

Debug.h

#ifndef DEBUG_H
#define DEBUG_H

class Debug {
  private:
    bool _state;
  public:
    Debug();
    void begin();
    void line(const char *str);
    void line(int);
    void newline();
};

#endif

Puzzle.cpp

#include "Puzzle.h"
#include "Box.h"

Puzzle::Puzzle()
  : _box(_debug)
{
}

void Puzzle::setup()
{
  _box.begin();
  _debug.begin();
  _debug.line("Puzzle Setup");
}

void Puzzle::loop()
{
}

Puzzle.h

#ifndef PUZZLE_H
#define PUZZLE_H

#include "Debug.h"
#include "Box.h"

class Puzzle
{
  private:
    Debug _debug;
    Box _box;
    
  public:
    Puzzle();
    void setup();
    void loop();
};

#endif

Why do you need 2 instances of Debug?

when you do this:

class Box {
  private:
    Debug _debug;

You are saying that the Box instances will own their Debug instance (as an instance variable), so it's already instantiated for you. So you don't need to instantiate it again.

This should (untested) compile. You can get rid of some constructors
main.ino:

#include "Puzzle.h"
Puzzle puzzle;

void setup() {puzzle.setup();}
void loop() { puzzle.loop();}

Box.cpp

#include "Box.h"
#include <Arduino.h>

void Box::begin() {
  _debug.begin();
  pinMode(28, INPUT_PULLUP);
}

Box.h

#ifndef BOX_H
#define BOX_H
#include "Debug.h"
class Box {
  private:
    Debug _debug;
    
  public:
    void begin();
};
#endif

Debug.cpp

#include "Debug.h"
#include <Arduino.h>

Debug::Debug() : _state(false) {}

void Debug::begin() {
  if (_state == false)
  {
    Serial.begin(9600);
    _state = true;
  }
}

void Debug::newline() {
  if (_state)Serial.println();
}

void Debug::line(const char *messageChar) {
  if (_state)
  {
    const char *p;
    p = messageChar;
    while (*p)
    {
      Serial.print(*p);
      p++;
    }
    newline();
  }
}

void Debug::line(int messageInt) {
  if (_state) {
    Serial.print(messageInt);
    newline();
  }
}

Debug.h

#ifndef DEBUG_H
#define DEBUG_H
class Debug {
  private:
    bool _state;
  public:
    Debug();
    void begin();
    void line(const char *str);
    void line(int);
    void newline();
};
#endif

Puzzle.cpp

#include "Puzzle.h"
#include "Box.h"

void Puzzle::setup() {
  _box.begin();
  _debug.begin();
  _debug.line("Puzzle Setup");
}

void Puzzle::loop() {}

Puzzle.h

#ifndef PUZZLE_H
#define PUZZLE_H

#include "Debug.h"
#include "Box.h"

class Puzzle
{
  private:
    Debug _debug;
    Box _box;

  public:
    void setup();
    void loop();
};

#endif

@PieterP : The explanations you provided really cut through the issues I was hitting. I really appreciate it.

@johnwasser + @J-M-L : Thank you both for the code you provided. I understand class initialization (and how to pass references) a lot better.

This support really is keeping me going.

My impression is that the intent was for the Puzzle and Box to share a single Debug. My code above tries to use the Debug copy constructor. I think the better way to do that is to have Box keep a pointer to the Debug and have the constructor initialize that pointer:
Box.h

#ifndef BOX_H
#define BOX_H

#include "Debug.h"

class Box {
  private:
    Debug * _debug;
    
  public:
    Box(Debug &debug);
    void begin();
};

#endif

Box.cpp

#include "Box.h"
#include <Arduino.h>

Box::Box(Debug &debug) : _debug(&debug)
{
}

void Box::begin()
{  
  pinMode(28, INPUT_PULLUP);
}

or do has the HardwareSerial class does with Serial. You define a global instance that is known and used everywhere

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