Pages: [1]   Go Down
Author Topic: Class constructors with parameters  (Read 5467 times)
0 Members and 1 Guest are viewing this topic.
UK
Offline Offline
Jr. Member
**
Karma: 2
Posts: 90
It was like it when I found it
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi,

I'm having trouble creating an object based on a class I've written. The problem seems to be because the constructor for the class takes a parameter.

First some background. I've written a total of three classes, all of which I've tested and used in sketches without problems.  The problem comes when I attempt to declare objects based on these classes as private member variables in the header file of another class I'm writing.

Two of the classes have a basic default constructor with no parameters. The third class has a constructor that requires a parameter to be passed to it. The two classes that require no parameters can be declared without problems. The third class (the one that requires a parameter) causes a list of compiler errors. There doesn't actually seem to be a problem with the class itself, I can use it elsewhere, I just can't declare it as a private member in another class.

Here's my declaration(s).....
  private:
    // Member variables
    GSM smsEngine;                       // needed to process incoming and outgoing SMSs
    Misc miscFuncs;                      // needed for the 'split' and 'trim' functions.
    MySDFat configFile("tracker.txt");   // needed to allow access to the configuration file.

And here's the error...

In file included from C:\all_apps\arduino-0021\libraries\SMSinterface\SMSinterface.cpp:7:
C:\all_apps\arduino-0021\libraries\SMSinterface\/SMSinterface.h:30: error: expected identifier before string constant
C:\all_apps\arduino-0021\libraries\SMSinterface\/SMSinterface.h:30: error: expected ',' or '...' before string constant
C:\all_apps\arduino-0021\libraries\SMSinterface\SMSinterface.cpp: In member function 'int SMSinterface::validatePhoneNum(char*)':
C:\all_apps\arduino-0021\libraries\SMSinterface\SMSinterface.cpp:174: error: '((SMSinterface*)this)->SMSinterface::configFile' does not have class type
C:\all_apps\arduino-0021\libraries\SMSinterface\SMSinterface.cpp:184: error: '((SMSinterface*)this)->SMSinterface::configFile' does not have class type
C:\all_apps\arduino-0021\libraries\SMSinterface\SMSinterface.cpp:210: error: '((SMSinterface*)this)->SMSinterface::configFile' does not have class type
C:\all_apps\arduino-0021\libraries\SMSinterface\SMSinterface.cpp:234: error: '((SMSinterface*)this)->SMSinterface::configFile' does not have class type

What am I doing wrong?

Cheers
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 617
Posts: 49463
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Have you noticed that the Serial class has a begin() method? Ever wonder why?

On the Arduino, you have no control over when the constructors are called. So, the stuff that would normally go in a constructor is passed to the object by calling the begin method of the class.

Since you can't provide initializers for variables in the header file, you need to find another way to pass that initialization data. The begin() method to the rescue, again.

Your MySDFat class needs a begin method. Sometime after the MySDFat instance is created, you need to call the begin method, to pass it the default argument.
Logged

UK
Offline Offline
Jr. Member
**
Karma: 2
Posts: 90
It was like it when I found it
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks for the explanation Paul.

Cheers

Logged

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

Quote
On the Arduino, you have no control over when the constructors are called.

Wow, is that true? That would be ... creepy.

Quote
private:
   // Member variables
   GSM smsEngine;                       // needed to process incoming and outgoing SMSs
   Misc miscFuncs;                      // needed for the 'split' and 'trim' functions.
   MySDFat configFile("tracker.txt");   // needed to allow access to the configuration file.

In standard C++, the answer to this would be the following construction:

Code:
class MyClass {
   MySDFat configFile; // Declare variable in header file
   [...]
}
Code:
MyClass::MyClass()
:
   configFile(MySDFat("tracker.txt")) // Initalise with 'member initialiser' syntax in constructor.
{
   // Rest of constructor.
}

This way, you initialise the variable on creation. You can read up on this syntax here.

« Last Edit: January 09, 2011, 05:36:21 pm by Gido » Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 617
Posts: 49463
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Wow, is that true? That would be ... creepy.
When is the Serial constructor called? You don't know? Man, that's creepy.
Logged

Maitland, Australia
Offline Offline
Jr. Member
**
Karma: 1
Posts: 88
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

You can control the constructor calls with an initializer list. I've seen this kind of question on the forum a number of times; so I wrote it up. Here: http://arduinoetcetera.blogspot.com/2011/01/classes-within-classes-initialiser.html
Logged

There are 3 kinds of people in the world. Those who are good at maths, and those who aren't.

Essex, UK
Offline Offline
Full Member
***
Karma: 4
Posts: 150
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

"you can't control when the constructors are called" is more correctly phrased as "you can't control the order in which the constructors of objects declared at global scope is called."

They will all be called before main() but the order is undefined by the C++ standard and may even change between rebuilds.
Logged

Home of the Nokia QVGA TFT LCD hacks: http://andybrown.me.uk

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 617
Posts: 49463
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
"you can't control when the constructors are called" is more correctly phrased as "you can't control the order in which the constructors of objects declared at global scope is called."
True, when referring to just when the constructors are called.

But, you also can't control whether the constructors are called before or after the hardware initialization takes place. So, if you want to do things like set the mode of a pin, or enable the pull-up resistor, that should NOT be done in the constructor.
Logged

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

Quote
So, if you want to do things like set the mode of a pin, or enable the pull-up resistor, that should NOT be done in the constructor.

This then only goes for classes in global memory, right? But I can see it might be useful to avoid it in general, as to make sure the classes could be used in global memory.
Logged

Essex, UK
Offline Offline
Full Member
***
Karma: 4
Posts: 150
Arduino rocks
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Yes it's only for global (or static global) class constructors. The Arduino library functions that manipulate pins need to reference some globally declared data tables and, although gcc does initialize global data before global constructors, you'd be taking an unnecessary risk in assuming that will always be the case.

Also, the timer that controls millis() is initialized in main() which definitely will not have been called yet so that's another function you can't use.
Logged

Home of the Nokia QVGA TFT LCD hacks: http://andybrown.me.uk

Pages: [1]   Go Up
Jump to: