Passing parameters in constructors.

Hi,

I'm not sure how to handle parameters in a constructor.

I've modified a class I've written to accept a serial port as a parameter, the constructor looks a bit like this..

MiniGPS::MiniGPS(HardwareSerial *serialX)
{

I can now invoke my library from a sketch using this line....

MiniGPS gps1(&Serial1);

This all works fine, the problem comes when I want to use my library from another library. Before I made any changes this snippet (in the .h file of my other library) would work fine....

  private:
    // Member variables
    MiniGPS _gps();                           // GPS

Following the change to to the GPS library, I change the way it was invoked to this....

private:
    // Member variables
    MiniGPS _gps(&Serial1);                           // GPS

This works for a sketch, but doesn't work for another library. Why not, and what do I need to do to get it work?

The error message is..

expected identifier before '&' token

The background for this question is here in a previous post....

http://forum.arduino.cc/index.php?topic=267352.msg1886462#msg1886462

Thanks

Any libraries that your libraries use, must also be included. Check out the third bullet point: http://arduino.land/FAQ/content/1/3/en/what-does-the-ide-change-in-my-sketch.html

If you only have one library which only uses the core, you may need to include HardwareSerial.h or just Arduino.h.

This works for a sketch, but doesn't work for another library. Why not, and what do I need to do to get it work?

Does Serial1 have a value at the time the gps instance is created? Do you know when the gps instance is created?

Any libraries that your libraries use, must also be included

they are included, if they weren't then my library would never have worked would it?

Does Serial1 have a value at the time the gps instance is created?

Errrrr...... I guess not? how do I make sure it does?

Do you know when the gps instance is created?

I think it gets created when the higher-level library gets created (which happens in the setup() phase of the top-level sketch.)

I think it gets created when the higher-level library gets created

The library is created in a text editor. It is highly unlikely that an instance of the class gets created on the Arduino at that time.

(which happens in the setup() phase of the top-level sketch.)

No. That might be when an instance of the parent class gets created.

I suggest that you check out the fine folks at http://snippets-r-us.com. They are great with snippets. We, on the other hand, are pretty lousy.

But, don't get (too) discouraged. What you want to do CAN be done. We just need to see the context to determine how.

My original libraries are far too long to be included here, so I've created a cut-down but compile-able version here. (overview - the final objective is to have a GPS library where the serial port that the GPS module is physically connected to can be passed as a parameter)

Firstly, my low level library...
'TestA.h'

#ifndef TestA_h                         
#define TestA_h                        

extern "C" {
  #include <string.h>
}

#include <stdlib.h>                        
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"                       
#else
#include "WProgram.h"                      
#endif

class TestA  
{
  public:
    TestA(HardwareSerial *serialX);      // Constructor
    byte readPort();

  private:
    // Member variables
    HardwareSerial *_portX;

    // Private methods
};
#endif

and 'TestA.cpp'

extern "C" {
#include <string.h>
}
#include <stdlib.h>
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"                       
#else
#include "WProgram.h"                      
#endif
#include "TestA.h"                          

TestA::TestA(HardwareSerial *serialX)
{
  _portX = serialX;
  _portX->begin(57600);
}

byte TestA::readPort()
{
  while (_portX->available())
  {
    // Read from one port and write directly to stout
    Serial.print((char)_portX->read());
  }

}

And the sketch to demonstrate they work and allow 'Serial1' to be passed as a parameter...

#include <stdlib.h>                        
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"                      
#else
#include "WProgram.h"                      
#endif
#include <TestA.h>                        

int testNum=1;

TestA tst1(&Serial1);

void setup() 
{
  Serial.begin(115200);
  Serial.println("####################     START     ###############################");
  
}

void loop()
{
  tst1.readPort();
}

Now for the higher level library that references 'TestA'
'TestB.h'

#ifndef TestB_h                         
#define TestB_h                        

extern "C" {
  #include <string.h>
}

#include <stdlib.h>                        
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"                       
#else
#include "WProgram.h"                      
#endif
#include <TestA.h>                      

class TestB  
{
  public:
    TestB();      // Constructor
    byte readPort();

  private:
    // Member variables
    TestB _myGps(&Serial1);                           

    // Private methods
};
#endif

and 'TestB.cpp'....

extern "C" {
#include <string.h>
}
#include <stdlib.h>
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"                       
#else
#include "WProgram.h"                      
#endif
#include "TestB.h"                          
#include <TestA.h>                      

TestB::TestB()
{
}

byte TestB::readPort()
{
  _myGps.readPort();
}

And the sketch to demonstrate that this doesn't work!....

#include <stdlib.h>                        
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"                      
#else
#include "WProgram.h"                      
#endif
#include <TestA.h>                        
#include <TestB.h>                        

int testNum=1;

TestA tst2();

void setup() 
{
  Serial.begin(115200);
  Serial.println("####################     START     ###############################");
  
}

void loop()
{
  tst2.readPort();
}

So, in the first sketch I can call the library with "TestA tst1(&Serial1);" which all works fine, but when I attempt to do the same thing from with the library TestB I get

expected identifier before '&' token

Thanks

Ok, I’ve got a work-around. Basically, I’ve given up on passing a parameter to a constructor, and instead have created a new function called begin() to which I pass a number (byte) representing the serial port to use. Like this.....

void TestA::begin(byte port)
{
  switch (port) 
  {
    case 0:
      _portX = &Serial;
      break;
    case 1:
      _portX = &Serial1;
      break;
    case 2:
      _portX = &Serial2;
      break;
    case 3:
      _portX = &Serial3;
      break;
    default:
      break;
  }

  _portX->begin(57600);
}

The result is more-or-less the same, I have a GPS library that will work on any port. Still, it’s a shame I couldn’t get it to work as originally planned.

TestA tst2();

That is a function prototype, for a function called tst2 that takes no arguments, and returns a value of type TestA. Is that really what you meant?

Why is the second sketch trying to create a TestA with no arguments? A TestA requires a HardwareSerial object as input.

  private:
    // Member variables
    TestB _myGps(&Serial1);

Shouldn't that type be TestA?

but when I attempt to do the same thing from with the library TestB I get

I'm sure you get more than that.

The major changes needed are:

TestB::TestB(): _myGps(&Serial1)

in the source file and

    TestA _myGps;

in the header file for TestB.

Is that really what you meant?

Nope. I meant...

TestA tst2;

Shouldn't that type be TestA?

Correct!

I'm sure you get more than that.

Not originally, only after making some corrections.

The major changes needed are:
Code:
TestB::TestB(): _myGps(&Serial1)

Okay, I understand this bit "TestB::TestB()" - but what does the extra bit "_myGps(&Serial1)" actually do?

Thank you!

Okay, I understand this bit "TestB::TestB()" - but what does the extra bit "_myGps(&Serial1)" actually do?

It invokes the TestA constructor to create the instance of the TestA class, passing it the Serial1 address.

It invokes the TestA constructor to create the instance of the TestA class, passing it the Serial1 address.

Okay, something similar to what I was attempting to do with

  private:
    // Member variables
    TestB _myGps(&Serial1);

(the only difference being your method worked!)

Thanks for your help!