Pages: [1]   Go Down
Author Topic: Using a class instance as a class global. How?  (Read 711 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 5
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Im writing a library, but I hit a brick wall right at the beginning.

I need to include an instance of the NewSoftSerial in the class, and I need that instance to be a class global.

In other languages you can define a variable as a class type, then later call the constructor. But in C++ it looks like both happen at the same time.

Under private globals I defined:
NewSoftSerial _printer;

Then in the constructor, I have
_printer(_RX_Pin, _TX_Pin);

But this dosnt seem to work one bit. I get an error of "error: no matching function for call to 'NewSoftSerial::NewSoftSerial()'"

I completely understand why because NewSoftSerial has no function called NewSoftSerial with no parameters.

But how does one get around this?


The library code is below.

Code:
#ifndef Thermal_h
#define Thermal_h

#include <NewSoftSerial.h>
#include <WProgram.h>
#include <WConstants.h>

class Thermal{
  public:

    Thermal(int RX_Pin, int TX_Pin);

  private:
int _RX_Pin;
  int _TX_Pin;
NewSoftSerial _printer;
};

#endif





Code:

#include <NewSoftSerial.h>

#include <WProgram.h>
#include <WConstants.h>
#include "Thermal.h"


Thermal::Thermal(int RX_Pin, int TX_Pin){

_RX_Pin = RX_Pin;
_TX_Pin = TX_Pin;

_printer(_RX_Pin, _TX_Pin);
}

Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 452
Posts: 18694
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

One approach is to make it a pointer, then call the constructor at runtime. For example:

Code:
#include <NewSoftSerial.h>

#include <WProgram.h>
#include <WConstants.h>
#include "Thermal.h"

Thermal::Thermal(int RX_Pin, int TX_Pin){

_RX_Pin = RX_Pin;
_TX_Pin = TX_Pin;

_printer = new NewSoftSerial (_RX_Pin, _TX_Pin);
        _printer->begin (9600);
}

Thermal::~Thermal(){
delete _printer;
}


// testing

// new and delete operators
void *operator new(size_t size_) { return malloc(size_); }
void* operator new(size_t size_,void *ptr_) { return ptr_; }
void operator delete(void *ptr_) { free(ptr_); }

Thermal * foo;

void setup ()
{
  foo = new Thermal (2, 3);
}

void loop () {
  foo->_printer->println ("hello, world");
}

and:

Code:
#ifndef Thermal_h
#define Thermal_h

#include <NewSoftSerial.h>
#include <WProgram.h>
#include <WConstants.h>

class Thermal{
  public:

    Thermal(int RX_Pin, int TX_Pin);  // constructor
    ~Thermal();  // destructor

    NewSoftSerial * _printer;

  private:
int _RX_Pin;
   int _TX_Pin;
};

#endif

I tested this and it did output data from pin 3.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 5
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Perfect!
Thank you!

Do I need to do anything to mark this as solved?
Logged

Australia
Offline Offline
Jr. Member
**
Karma: 0
Posts: 99
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Or use a reference member and an initialization list:

Code:
#ifndef Thermal_h
#define Thermal_h

#include <NewSoftSerial.h>
#include <WProgram.h>
#include <WConstants.h>

class Thermal{
  public:

    Thermal(int RX_Pin, int TX_Pin);

  private:
int _RX_Pin;
  int _TX_Pin;
NewSoftSerial& _printer;
};

#endif

Code:
#include <NewSoftSerial.h>

#include <WProgram.h>
#include <WConstants.h>
#include "Thermal.h"


Thermal::Thermal(int RX_Pin, int TX_Pin):
_printer(RX_Pin, TX_Pin), _RX_Pin(RX_Pin), _TX_Pin(TX_Pin) {}
« Last Edit: August 10, 2011, 06:56:48 pm by crimony » Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 452
Posts: 18694
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Or use a reference member and an initialization list: ...

Yes, that gets rid of pointers, but I can't get it to compile:

Code:
Thermal.cpp: In constructor 'Thermal::Thermal(int, int)':
Thermal:8: error: member initializer expression list treated as compound expression
Thermal:8: error: invalid initialization of reference of type 'NewSoftSerial&' from expression of type 'int'

A bit of fiddling around to remove the error gives this:

Code:
#ifndef Thermal_h
#define Thermal_h

#include <NewSoftSerial.h>
#include <WProgram.h>
#include <WConstants.h>

class Thermal{
  public:

    Thermal(int RX_Pin, int TX_Pin);
NewSoftSerial _printer;

  private:
int _RX_Pin;
  int _TX_Pin;
};
#endif

Code:
#include <NewSoftSerial.h>

#include <WProgram.h>
#include <WConstants.h>
#include "Thermal.h"

Thermal::Thermal(int RX_Pin, int TX_Pin):
_printer(RX_Pin, TX_Pin), _RX_Pin(RX_Pin), _TX_Pin(TX_Pin) {
       _printer.begin (9600);
}

// testing

Thermal foo (2, 3);

void setup ()
{
}

void loop () {
  foo._printer.println ("hello, world");
}

That works, although I caution you that this is using a static constructor. Although it worked this time, static constructors can sometimes give weird results because of the order the constructors are called during program initialization.
Logged

Australia
Offline Offline
Jr. Member
**
Karma: 0
Posts: 99
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset


Yes, that gets rid of pointers, but I can't get it to compile:

My bad, I didn't test at all, and my C++ is very rusty.

The point was supposed to be that you need to use an initialization list if there is no default constructor for a member variable (in this case class NewSoftSerial).

Quote
That works, although I caution you that this is using a static constructor. Although it worked this time, static constructors can sometimes give weird results because of the order the constructors are called during program initialization.

I expect undefined behaviour if the constructor for NewSoftSerial is called in the global variable initialization stage.
Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 452
Posts: 18694
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I expect undefined behaviour if the constructor for NewSoftSerial is called in the global variable initialization stage.

Where were you planning to put the declaration for Thermal then? In my case:

Code:
Thermal foo (2, 3);

I had it at global scope, so it would be constructed at global initialization time, and thus the constructor for NewSoftSerial likewise.

If you put it into setup, it goes out of scope once setup ends.

If you put it into loop, it is constructed every time through the loop.

If you put it into loop, declared static, like this:

Code:
void loop () {
  static Thermal foo (2, 3);

  foo._printer.println ("hello, world");
}

Then you get the error:

Code:
Thermal.cpp.o: In function `loop':
Thermal.cpp:23: undefined reference to `__cxa_guard_acquire'
Thermal.cpp:23: undefined reference to `__cxa_guard_release'
Thermal.cpp:23: undefined reference to `atexit'
Logged

Australia
Offline Offline
Jr. Member
**
Karma: 0
Posts: 99
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I expect undefined behaviour if the constructor for NewSoftSerial is called in the global variable initialization stage.

Where were you planning to put the declaration for Thermal then?

My expectations are unrealistic, as it turns out. Global scope is the right thing to do.

On closer inspection of the NewSoftSerial Library, it appears they must have ensured that they are immunized from the kind of initialisation issues covered here.

Logged

Pages: [1]   Go Up
Jump to: