C++ how to call one constructor from another, happy to pay for some consulting time

Status
Not open for further replies.

bboyes

Well-known member
If this is too off-topic and someone can point to a resource elsewhere I will be grateful. I have googled and tried a number of approaches so far to no success. I am needing to call one constructor from another. Here's what I am trying to do. I have an I2C register class (PCA9557) since on our board there are multiple of these. Each one generates a complex bit stream to talk to an off-board chain of shift registers which are part of legacy hardware we are controlling. So the PCA9557 class gets instantiated passing it the I2C base address. That all works fine and an example program (all in the Github repo) works well.

Code:
/**
 * These are the addresses of the I2C devices which drive the related Core DB15 connector 
 */
#define I2C_J2 0x1B
#define I2C_J3 0x1A
#define I2C_J4 0x19

// and later in the example .ino file, outside of the scope of setup() and loop(), where other data is declared, I declare these class instances:
Systronix_PCA9557 coreJ2(I2C_J2);
Systronix_PCA9557 coreJ3(I2C_J3);
Systronix_PCA9557 coreJ4(I2C_J4);

// now I have coreJ2, coreJ3, coreJ4 which can drive their own appropriate PCA9557

Now I also want to have a higher layer library of functions and data which generates a complex 32-bit stream to be sent to one of these coreJ2, coreJ3, coreJ4. Each instance of that higher level library is associated with one of the PCA9557 registers.

So the higher library has a constructor, I can also pass it the PCA9557 base address which it could pass on and create the appropriate instance of the PCA9557. But every way I try to do that fails. Due to my ignorance of how C++ does this (I've most recently been a Java guy) these probably look laughable. The higher library class def looks like this
Code:
class SALT_JX
{
	protected:
		uint32_t	_DC_data_in;			// data the update() is reading from the DC board '165 shift register
		//Systronix_PCA9557 coreJXreg;		// the instance of PCA_9557 which is tied to this SALT_JX instance, this is not right, I need to pass base address
		Systronix_PCA9557 coreJXreg(uint8_t);   // nope this doesn't work either


	public:
		SALT_JX (uint8_t);			// constructor, I2C base address
		void begin (void);					
		void init (void);					
		void update(void);                       // this is the function which will send a long bitstream eventually out the pins on the PCA9557 to downstream shift registers
                // more class def

This must be a common question but googling has not led me to the answer. Thanks in advance for any help!

BTW if anyone out there is a C++ guru and can spare a few hours of consulting time I am more than happy to pay you for some oversight and assistance either PayPal $$ or I have too many Raspi and Beaglebone Black, and could send you some hardware.
 
Last edited:
I have ran into this problem before as well. I have no idea if this is the "correct" solution so YMMV.

My understanding of your issue is you want to make a "Systronix_PCA9557" object inside one of your classes. But the compiler throws a fit and a very unhelpful error. Trying to call "coreJXreg;" without the initial passed in value also throws errors as it doesn't exist within the Systronix_PCA9557 class.

My solution was to create a "setup" function within the class i wanted to create an object of. So you could try editing the library;

In the Systronix_PCA9557.cpp file:

Code:
/**************************************************************************/
Systronix_PCA9557::[B]Systronix_PCA9557[/B](uint8_t base)  //<- Edit This!
{
	_base = base;
	BaseAddr = base;
//	static data _data;		// instance of the data struct
//	_data.address = _base;	// struct
	_inp_data = 0;
	_out_data = 0;
	_invert_mask = 0;

}

becomes:

Code:
/**************************************************************************/
void Systronix_PCA9557::[B]setup[/B](uint8_t base)//<- To This!
{
	_base = base;
	BaseAddr = base;
//	static data _data;		// instance of the data struct
//	_data.address = _base;	// struct
	_inp_data = 0;
	_out_data = 0;
	_invert_mask = 0;

}

and the .h file:

Code:
public:
		[B]Systronix_PCA9557[/B](uint8_t base);		// constructor //<- Edit This!
		void begin(void);	// joins I2C as master
		void init(uint8_t out_mask, uint8_t out_data, uint8_t inp_invert);	// sets regs
		uint8_t control_write (uint8_t data);
		uint8_t register_write (uint8_t reg, uint8_t data);
		uint8_t default_read ();
		uint8_t BaseAddr;    // I2C address, only the low 7 bits matter

		uint8_t pin_pulse (uint8_t pin_mask, boolean idle_high);
		uint8_t pin_drive (uint8_t pin_mask, boolean high);
		
		uint8_t input_read ();
		uint8_t output_read ();

	private:

becomes


Code:
public:
	    [B]void setup[/B](uint8_t base);		//<- To This! new setup function
		void begin(void);	// joins I2C as master
		void init(uint8_t out_mask, uint8_t out_data, uint8_t inp_invert);	// sets regs
		uint8_t control_write (uint8_t data);
		uint8_t register_write (uint8_t reg, uint8_t data);
		uint8_t default_read ();
		uint8_t BaseAddr;    // I2C address, only the low 7 bits matter

		uint8_t pin_pulse (uint8_t pin_mask, boolean idle_high);
		uint8_t pin_drive (uint8_t pin_mask, boolean high);
		
		uint8_t input_read ();
		uint8_t output_read ();

	private:


then in your class:
Code:
class SALT_JX
{
	protected:
		uint32_t	_DC_data_in;			// data the update() is reading from the DC board '165 shift register
		Systronix_PCA9557 coreJXreg;		// in your class setup code you will require to run the setup function you've created for Systronix_PCA9557


I used this method to get the PID library embedded into one of my classes. As i say, i'm not sure if this is the "correct" solution and may crop up as an issue in the future. However, there are many arduino classes that require a "setup" call in the beggining so i'm not sure it's "wrong" to do it this way.

Good Luck,
JW
 
There are various ways to initialize member objects, you can use initializer lists in your constructor (classes A and B below) and or the new C++11 brace-init thingy (class C).

Code:
class Base
{
    int value_;

public:
    Base(int value)
        : value_(value)
    {
    }
};

class A
{
    Base base_;

public:
    A(int value)
        : base_(value)
    {
    }
};

class B
{
    Base base_;

public:
    B()
        : base_(5)
    {
    }
};

// This is C++11 only, which should be fine for Arduino
class C
{
    Base base_{5};
};
 
You probably want to look up c++ superclasses and sub-classes. While I do some lite C++ programming, I tend to be a C programmer at heart.

I have my own Neopixel library for doing common patterns (chase, theater, breathe, etc.). One of the base header files is the sub-class for actions:

Code:
/*
 * Container class for the various Neopixel actions.
 */

class Neopixel_action {
 protected:
  Delay		   timeout;					// timeout structure
  Neopixel_object *neopixel;					// neopixels to use
  unsigned long	   delay_small;					// small delay (between elements in a pattern)
  unsigned long	   delay_large;					// large delay (between patterns)
  Neopixel_iter_t  iterations;					// current number of iterations to use before returning false
  Neopixel_iter_t  min_iterations;				// minimum number of iterations to use before returning false
  Neopixel_iter_t  max_iterations;				// maximum number of iterations to use before returning false
  Neopixel_index_t num_pixels;					// number of neopixels that are logically present.
  Neopixel_power_t brightness;					// max brightness to use

 public:
  // constructor/destructor
  Neopixel_action (Neopixel_iter_t	min_iter	= 1,
                   Neopixel_iter_t	max_iter	= 1,
		   Neopixel_power_t	bright		= 0,
		   unsigned long	dsmall		= 125,
		   unsigned long	dlarge		= 3000);

  ~Neopixel_action (void);

  // Function to set up the actions, possibly setting iterations or brightness levels
  virtual void start (Neopixel_iter_t  iter   = 0, Neopixel_power_t bright = 0) = 0;

  // Function called from the main loop function to possibly do the next action.
  // Return false, when all of the current actions are finished.
  // If do_show_p is not a NULL pointer, the function will not call show, but
  // instead set *do_show_p to true.
  virtual bool loop (bool *do_show_p = NULL) = 0;

  // Return a string giving the name of the action for debugging
  virtual const char *name (void) = 0;

  // Return the number of logical pixels
  Neopixel_index_t max_pixels (void)
  {
    if (num_pixels == 0 && neopixel)
      num_pixels = neopixel->max_pixels ();

    return num_pixels;
  }
};

The constructor in the .cpp file looks like:

Code:
/*
 * Container class for the various Neopixel actions.
 */

Neopixel_action::Neopixel_action (Neopixel_iter_t	min_iter,
				  Neopixel_iter_t	max_iter,
				  Neopixel_power_t	bright,
				  unsigned long		dsmall,
				  unsigned long		dlarge)

  :	timeout		(Delay ()),
	neopixel	((Neopixel_object *)0),
	delay_small	(dsmall),
	delay_large	(dlarge),
	iterations	(0),
	min_iterations	(min_iter),
	max_iterations	(max_iter),
	num_pixels	(0),
	brightness	(bright)
{
}

Neopixel_action::~Neopixel_action (void)
{
}

Now, one of the action files uses Neopixel_action as a sub-class. Here is the class definition:

Code:
class Neopixel_red_green : Neopixel_action {
 private:
  // Normally we would use Neopixel_power_t for red/green, but we want a larger type
  // that is signed to make some tests simpler.
  int                   red;                                    // current red brightness
  int                   green;                                  // current green brightness
  Neopixel_power_t      bright_step;                            // step in changing the brightness
  bool                  do_red;                                 // whether we are increasing red or green

 public:
  // constructor/destructor
  Neopixel_red_green (Neopixel_power_t  bright          = RED_GREEN_BRIGHTNESS,
                      Neopixel_power_t  step            = RED_GREEN_BRIGHT_STEP,
                      Neopixel_iter_t   min_iter        = RED_GREEN_MIN_ITERATIONS,
                      Neopixel_iter_t   max_iter        = RED_GREEN_MAX_ITERATIONS,
                      unsigned long     delay_fade      = RED_GREEN_DELAY_FADE,
                      unsigned long     delay_whole     = RED_GREEN_DELAY_WHOLE);

  ~Neopixel_red_green (void);

  // begin function to initialize everything (non-zero changes the default from the constructor)
  void begin (Neopixel_object  *neo,
              Neopixel_power_t  bright                  = 0,
              Neopixel_power_t  step                    = 0,
              Neopixel_iter_t   min_iter                = 0,
              Neopixel_iter_t   max_iter                = 0,
              unsigned long     delay_fade              = 0,
              unsigned long     delay_whole             = 0);

  // Function to set up the actions, possibly setting iterations or brightness levels
  void start (Neopixel_iter_t  iter   = 0,
              Neopixel_power_t bright = 0);

  // Function called from the main loop function to possibly do the next
  // action.  Return false, when all of the current actions are finished.  If
  // do_show_p is not a NULL pointer, the function will not call show, but
  // instead set *do_show_p to true.  It is assumed that the user has set
  // *do_show_p to false before the call.
  bool loop (bool *do_show_p = NULL);

  // Return a string giving the name of the action for debugging
  const char *name (void)
  {
    return "Red_Green";
  }
};

Note, you have class <superclass> : <subclass>, that denotes <superclass> uses <subclass> as a base class. You can have multiple <subclass>'s, but that can get complex quickly.

And the constructor in the .cpp file looks like:

Code:
// Constructor, destructor
Neopixel_red_green::Neopixel_red_green (Neopixel_power_t bright,
					Neopixel_power_t step,
					Neopixel_iter_t  max_iter,
					Neopixel_iter_t  min_iter,
					unsigned long	 delay_inner,
					unsigned long	 delay_whole)

      :	Neopixel_action (max_iter, min_iter, bright, delay_inner, delay_whole),
	red	     (bright),
	green	     (0),
	bright_step  (step),
	do_red	     (true)
{
}

Neopixel_red_green::~Neopixel_red_green (void)
{
}

Note, where after the ':', it then provides the constructor for the sub-class.

You might want to browse: http://www.learncpp.com/cpp-tutorial/114-constructors-and-initialization-of-derived-classes/, or start at the top of the site: http://www.learncpp.com/.

And I agree with Paul, that if possible, you want to push most initialization into a setup/begin function, due to the issue of static initializer priority startup, and possibly use a pointer to the class in the secondary class rather than initialize it statically.
 
Last edited:
If I understand what you want correctly, you are looking for this:
Code:
class Systronix_PCA9557 {
public:
    Systronix_PCA9557(uint8_t base);
};

class SALT_JX {
protected:
    Systronix_PCA9557 coreJXreg;
public:
    SALT_JX(uint8_t base);
};

SALT_JX::SALT_JX(uint8_t base) : coreJXreg(base) {
}

The term you are looking for is "Initializer List" - that's how you initialize member objects of a class. If the constructor of the member doesn't take parameters, it's called automatically without you having to include it in the initializer list.
 
Wow thanks to all for some great answers. Java too has a "you never know the order of constructors" issue, plus if a constructor throws an exception there is not much you can do about it. So the Setup/Begin seems a better solution, since you could recover or handle things like hardware downstream that seems offline. Also this morning the idea of subclassing/extending the PCA9557 class seemed maybe like what we really want, though I am not 100% sure. Every _JX class instance can have an "embedded" PCA9557 instance and extend those low level functions so that seems logical to me. Yeah @MichaelMeissner I tend to be a pretty simple-minded C coder, having done mostly low level I/O drivers and hardware control where reliability and 100% uptime are the goals. Without C++ on this project we would have a lot of duplicated code, with more chance for errors, so I am happy to have this struggle since it also holds the promise of a Better Solution.

@tni this looks good conceptually. Thanks @JWScotSat and @Koromix, my head is spinning with all this new information. I can't say I ever fully grokked Java classes but did get to the point where I could get useful things done... hope to be there soon with C++. Thanks again...
 
Wow thanks to all for some great answers. Java too has a "you never know the order of constructors" issue, plus if a constructor throws an exception there is not much you can do about it. So the Setup/Begin seems a better solution, since you could recover or handle things like hardware downstream that seems offline.
With Arduino you don't get to use exceptions, so you can't directly signal errors from the constructor. Anything that can fail and should possibly be retried should not be part of the constructor.
Also this morning the idea of subclassing/extending the PCA9557 class seemed maybe like what we really want, though I am not 100% sure. Every _JX class instance can have an "embedded" PCA9557 instance and extend those low level functions so that seems logical to me.
If you even have a small doubt, inheritance is most likely the wrong design choice. Do you want to be able to pass _JX to something that expects a PCA9557 class? If no, don't use inheritance.
 
@tni no we don't want to want to be able to pass _JX to something that expects a PCA9557 class so thanks for that... when I figure this out I will post the winning solution here. True Arduino doesn't have try-catch Exceptions like Java but any function can return a status code, and I try to use those since what is the point of continuing to talk to downstream hardware if it is not responding or might be powered down or unplugged? Or how can we make a decision about setpoint temperature if sensors are not returning believeable data? I should have said "exception handling".
 
Construct on first use is working well!

@JWScotSat Thanks for your detailed reply! I am happy to report that we have a working version of the "construct on first use" idiom, from Pauls reference and your implementation tips. Hopefully it works because we did it correctly and not because we're lucky. Here are some details of the implementation in hopes they are useful to someone else. Also the

Code:
In my higher level JX class .h file:
#define I2C_J2 0x1B     // I2C base address for each 9557 which drives one of three J2, J3, J4 DB15 connectors
#define I2C_J3 0x1A
#define I2C_J4 0x19
...
class JX
{
	protected:
		// the instance of PCA_9557 which is tied to this SALT_JX instance, this just declares but doesn't construct it
		// This is protected so that scope is limited to the SALT_JX class, the application has no direct PCA9557 access
		Systronix_PCA9557 coreJXreg;	
	public:
		void setup(uint8_t);				// constructor, pass the PCA9557 I2C base address 
		void begin (void);				// just once at start of program, combine with setup()?
		uint8_t init (void);				// returns 0 if success

Code:
In the JX library .cpp file:
void JX::setup(uint8_t I2C_base)
	{
		// really construct the PCA9557 instance specific to this JX instance
		coreJXreg.setup(I2C_base);		
	}

and in the PCA9557 library .cpp:
Code:
void Systronix_PCA9557::setup(uint8_t base)
{
	_base = base;      // used later in I2C read and write by Wire.beginTransmission(_base)
	BaseAddr = base;
        // other data setup follows
}

Finally in the application which uses both the JX and PCA9557 libraries:
decared outside of setup and loop:
Code:
// make an instance of JX specific to J2 and the PCA9557 at the passed I2C address 
JX coreJ2;		
...
void setup(void)
       {
	// construct both J2 and PCA9557
	coreJ2.setup(I2C_J2);
        coreJ2.begin();
	coreJ2.init();
        ...
        } 

void loop(void) 
	{
        // other uses of coreJ2, which uses the high level functions in JX lib and in turn the low level functions in PCA9557 lib
        coreJ2.update ();
        }

Since JX declares the 9557 "protected" the application can use JX but NOT the PCA9557 functions directly, which is part of what we hoped to accomplish. We want those low level functions encapsulated and accessed only through the JX API.

So now we have only one generic library for the PCA9557 and another generic library for the JX connectors, with example/test programs for each. The application just has to instantiate three JX, and that automatically makes a matching PCA9557 for each JX, then the data to and from each is independent. So nothing low-level is hard coded, and we only have generic libraries to maintain, so less chance of bugs and should be easier to maintain over the product life.

Thanks again! I owe you all a beer or 4, esp Paul and JWScotSat, but all inputs were helpful. What a great support community. I hope I can return the favor. I have two C++ books to pick up at the library. Seriously if any of you are in SLC, UT look me up. Lunch is on me. I will also be in Portland at the Open Hardware Summit in Oct, same offer there. Or if you are at OpenWest here in UT next week.
 
Last edited:
Status
Not open for further replies.
Back
Top