2

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!

5
  • Might be more of a programming question as an Arduino question. I've heard that ENUM's are specifically useful when dealing with switch-case statements, since you can define a "default" case.
    – aaa
    Commented Mar 18, 2016 at 15:32
  • You can define a 'default' case on a switch statement without needing an enum, but for me it will help the code be more usable as you can give each case a name and not just a number.
    – Rob Hilken
    Commented Mar 18, 2016 at 16:38
  • SHouldn't CandleRack MyCandleRack(0); be CandleRack 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.
    – Steve
    Commented Mar 18, 2016 at 17:10
  • The enum gives the object its properties so my logic tells me it should be a part of the class, it's also a private member so it's properties are hidden from all of the other classes I will be adding. You're right about MyCandleRack(inactive); though.
    – Rob Hilken
    Commented Mar 18, 2016 at 17:44
  • Hmm, you're true on the default thing. But I can vaguely remember my prof being "mad" at me for using defines instead of enums, since your compiler could check if all enums are handled in your switch-case.
    – aaa
    Commented Mar 18, 2016 at 19:01

2 Answers 2

4

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
}
5
  • 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
    Commented 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
    Commented 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
    Commented 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
    Commented 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
    Commented Mar 20, 2016 at 11:49
0

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!

6
  • It seems this answer compiles the gist of my answer into a code-only post (see e.g. meta.stackexchange.com/questions/148272/…)
    – sekdiy
    Commented 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
    Commented 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
    Commented Mar 19, 2016 at 10:20
  • In this example where is status coming from? status_t status = inactive
    – Rob Hilken
    Commented Mar 19, 2016 at 10:36
  • status is an alternative naming to your candleRackStatus. 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
    Commented Mar 19, 2016 at 12:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.