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
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.
On the Arduino, you have no control over when the constructors are called.
Wow, is that true? That would be ... creepy.
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:
class MyClass {
MySDFat configFile; // Declare variable in header file
[...]
}
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.
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: Classes within Classes - Initialiser Lists
"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.
"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.
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.
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.