I am trying to set the status of an object from a private enum and I'm not sure how to get the private member to the public version in the constructor, and I'm pretty sure I should not be using byte
in the constructor when it's an enum.
Also, I'm not sure if I should even have the values of the enum inside the header at all. Here is my code:
.h
class CandleRack
{
public:
CandleRack(byte candleRackStatus);
~CandleRack();
void begin();
void pushButton();
void selectRandomCandle();
void turnOnCandle(byte candlePosition);
void burnCandlesForMs();
void fadeOutCandle(byte candlePosition);
private:
Bounce *_debouncePushButton;
byte _pushButtonPin;
enum _candleRackStatus
{
inactive = 0,
candlesOn = 1,
rewardAnimation = 2,
tweetArrived = 3,
partyMode = 4,
};
byte _candlePosition;
byte _candleStatus[NUM_LEDS];
elapsedMillis _candleTimeElapsed[NUM_LEDS];
unsigned int _candleOnForMs;
};
.cpp
CandleRack::CandleRack(byte candleRackStatus)
{
_candleRackStatus = candleRackStatus;
_debouncePushButton = NULL;
}
in the sketch
CandleRack MyCandleRack(0);
error:
error: expected unqualified-id before '=' token
_candleRackStatus = candleRackStatus;
Thanks!
2 Answers 2
I see two separate issues here.
First of all your enum isn't available as a variable. By declaring it as a private type within your class the enum can't be used outside of that class.
This forces a user of that class to handle unintended calls like (attention, bug):
CandleRack(255);
which can make code harder to read (and debugging more difficult, since it wouldn't be detected by the compiler).
Second of all you try to directly assign a byte value to an enum type. This will be rejected by the compiler and/or cause runtime errors later (depending on compiler settings).
I recommend that you declare the enum type so that it is accessible directly via the header file:
.h
enum CandleRackStatus {
inactive = 0,
candlesOn = 1,
rewardAnimation = 2,
tweetArrived = 3,
partyMode = 4,
};
class CandleRack
{
public:
CandleRack(CandleRackStatus candleRackStatus);
~CandleRack();
void begin();
void pushButton();
void selectRandomCandle();
void turnOnCandle(byte candlePosition);
void burnCandlesForMs();
void fadeOutCandle(byte candlePosition);
private:
Bounce *_debouncePushButton;
CandleRackStatus _candleRackStatus;
byte _pushButtonPin;
byte _candlePosition;
byte _candleStatus[NUM_LEDS];
elapsedMillis _candleTimeElapsed[NUM_LEDS];
unsigned int _candleOnForMs;
};
Now you can instantiate your class while using the correct enum type as the parameter.
.ino
CandleRack MyCandleRack(CandleRackStatus::inactive);
Within your implementation you can now directly store the constructor parameter in the private variable, the compiler will make sure it's always of the correct enum type:
.cpp
CandleRack::CandleRack(CandleRackStatus candleRackStatus) {
_candleRackStatus = candleRackStatus;
// rest of your initialisiation goes here
}
As an added bonus, there's the possibility to use a couple of C++ language features that will make your implementation easier:
.h
class
{
public:
CandleRack(CandleRackStatus candleRackStatus = CandleRackStatus::inactive);
// [...]
}
.cpp
CandleRack::CandleRack(CandleRackStatus candleRackStatus) : _candleRackStatus(candleRackStatus) {
// rest of your initializiation goes here
}
-
One thing I don't understand is why you have Capitalized the name CandleRackStatus. I thought an enum was just a variable and nothing like a class or struct. I think it's confusing to treat it like a class (with naming conventions) ...Rob Hilken– Rob Hilken2016年03月20日 09:49:00 +00:00Commented Mar 20, 2016 at 9:49
-
last question, when I actually want to change the status of the CandleRack, do I do
_candleRackStatus = candlesOn
?Rob Hilken– Rob Hilken2016年03月20日 10:34:00 +00:00Commented Mar 20, 2016 at 10:34 -
Re: Capitalized, that's a matter of taste and what school of programming you come from. I recommend treating enums like types, because they are. And in most C++ styles types get a capitalized name. See google.github.io/styleguide/cppguide.html#Enumerator_Names for reference, also a good read as a whole.sekdiy– sekdiy2016年03月20日 11:36:22 +00:00Commented Mar 20, 2016 at 11:36
-
Re: changing the status, the identifier
candlesOn
is defined within the type declaration of the enum. So in order to access it you would qualify it with the type name:CandleRackStatus::candlesOn
. That's called static access and the::
operator works on all type properties that are public and static (see stackoverflow.com/questions/10090949/…). So you would change the status using_candleRackStatus = CandleRackStatus::candlesOn
.sekdiy– sekdiy2016年03月20日 11:46:34 +00:00Commented Mar 20, 2016 at 11:46 -
We've discussed simplification of names before, so if these expressions are too lengthy or confusing, just choose shorter names for types and variables.sekdiy– sekdiy2016年03月20日 11:49:54 +00:00Commented Mar 20, 2016 at 11:49
How about this refactoring?
class CandleRack
{
public:
enum status_t
{
inactive = 0,
candlesOn = 1,
rewardAnimation = 2,
tweetArrived = 3,
partyMode = 4,
};
CandleRack(status_t status = inactive);
~CandleRack();
void begin();
void pushButton();
void selectRandomCandle();
void turnOnCandle(byte candlePosition);
void burnCandlesForMs();
void fadeOutCandle(byte candlePosition);
private:
Bounce *_debouncePushButton;
byte _pushButtonPin;
status_t _candleRackStatus;
byte _candlePosition;
byte _candleStatus[NUM_LEDS];
elapsedMillis _candleTimeElapsed[NUM_LEDS];
unsigned int _candleOnForMs;
};
And in a sketch with either the default setting (inactive)
CandleRack MyCandleRack;
or explicit
CandleRack MyCandleRack(CandleRack::candlesOn);
Cheers!
-
It seems this answer compiles the gist of my answer into a code-only post (see e.g. meta.stackexchange.com/questions/148272/…)sekdiy– sekdiy2016年03月18日 22:19:18 +00:00Commented Mar 18, 2016 at 22:19
-
Yes It does a bit. If you could add some of these suggestions to your post I think that would make it a great answer. Especially as this shows how I could use the enum as a public member and not outside of the class - which in my mind, makes it more understandable.Rob Hilken– Rob Hilken2016年03月19日 10:19:15 +00:00Commented Mar 19, 2016 at 10:19
-
But also thanks to Mikael for this post too, it also helps my understanding of how to use enums.Rob Hilken– Rob Hilken2016年03月19日 10:20:17 +00:00Commented Mar 19, 2016 at 10:20
-
In this example where is
status
coming from?status_t status = inactive
Rob Hilken– Rob Hilken2016年03月19日 10:36:00 +00:00Commented Mar 19, 2016 at 10:36 -
status
is an alternative naming to yourcandleRackStatus
. Simpler names can increase readability. Since you only pass one parameter, you don't really need to qualify it in more detail than neccessary, so it's probably a good idea to simplify. :) I've updated my answer to explain the use of the enum type and a default parameter value.sekdiy– sekdiy2016年03月19日 12:35:29 +00:00Commented Mar 19, 2016 at 12:35
switch-case
statements, since you can define a "default" case.CandleRack MyCandleRack(0);
beCandleRack MyCandleRack(inactive);
or maybe CandleRack::inactive. My C++ is a bit rusty (very rusty). Also, in the interests of program readability the enum would be useful outside the class otherwise you're just assigning a bunch of numbers.MyCandleRack(inactive);
though.