Click here to Skip to main content
11,429,154 members (62,450 online)
Click here to Skip to main content

Enum vs Const

, 5 Oct 2003 CPOL
Rate this:
Please Sign up or sign in to vote.
Enum vs Const - why...

Introduction

I recently had to review some c++ code written by someone else. The code was well written. It checked for error conditions and did reasonable things if something went wrong. But there was something about it that irked me.

For obvious reasons I'm not showing the real classes. Instead I'll illustrate the irksome thing with contrived examples.

The Original Class

The class I was reviewing ran something like this.
class CAClass
{
public:
    static const UINT aConstantOfInterestToThisClass1 = 0;
    static const UINT aConstantOfInterestToThisClass2 = 1;

    CAClass(UINT constValue, LPCTSTR someOtherParameter);

    void DoSomething();

private:
    UINT    m_const;
    CString m_parameter;
};

The class CAClass constructor takes a parameter that specifies something of interest to the class, constValue and a pointer to a string. DoSomething() does something relevant based on the parameters passed to the constructor. The class implementation was coded something like this.

CAClass::CAClass(UINT constValue, LPCTSTR someOtherParameter)
{
    m_const = constValue;
    m_parameter = someOtherParameter;
}
    
void CAClass::DoSomething()
{
    switch (m_const)
    {
    case aConstantOfInterestToThisClass1:
        //  Do something defined by this constant.
        break;

    case aConstantOfInterestToThisClass2:
        //  Do something defined by this constant.
        break;

    default:
        //  It's not a valid value, raise an exception
        RaiseException(ERROR);
        break;
    }
}

This code will work fine. So what's wrong with it?

How I'd have coded it

class CBClass
{
public:
    enum constsOfInterestToThisClass
    {
        bConstantOfInterestToThisClass1 = 0,
        bConstantOfInterestToThisClass2,  // The value will be the 'next' 
                                          // value
    };

    CBClass(constsOfInterestToThisClass constValue,
            LPCTSTR someOtherParameter);

    void DoSomething();

private:
    constsOfInterestToThisClass m_const;
    CString m_parameter;
};

and the implementation...

CBClass::CBClass(constsOfInterestToThisClass constValue,
                 LPCTSTR someOtherParameter)
{
    m_const = constValue;
    m_parameter = someOtherParameter;
}
    
void CBClass::DoSomething()
{
    switch (m_const)
    {
    case bConstantOfInterestToThisClass1:
        //  Do something defined by this constant.
        break;

    case bConstantOfInterestToThisClass2:
        //  Do something defined by this constant.
        break;

    default:
        //  It's not a valid value, raise an exception
        //  We should never get here...
        RaiseException(ERROR);
        break;
    }
}

There's almost no difference. Any good c++ compiler would compile identical code for both classes.

So what's the difference?

The first class, CAClass, defines a bunch of constant values of interest to itself. CBClass defines the same named constants but it does it as an enum. An enum defines a limited set of valid values and can also be used as a pseudo datatype. Look at the difference in the definitions of the constructors.
CAClass(UINT constValue, LPCTSTR someOtherParameter);

CBClass(constsOfInterestToThisClass constValue, LPCTSTR someOtherParameter);

CAClass can accept any valid UINT value. That's over 4 billion possible values, only 2 of which are of any possible interest to the class. Any valid UINT value outside of 0 or 1 will cause the DoSomething function to raise an exception that other code within your application must handle.

CBClass in contrast will accept only one of the two enum values. Try and pass any invalid constant and the compiler will (should) complain with an error or warning message.

Contrast this

CAClass obj(1000, _T("This is a string"));

obj.DoSomething();

with this

CBClass obj(1000, _T("This is a string"));

obj.DoSomething();

The first example CAClass obj(1000, _T("This is a string")); will compile and throw an exception at runtime when it calls obj.DoSomething(). The second example CBClass obj(1000, _T("This is a string)); will at the very least throw up an error message in your compiler, at compile time. A good implementation will fail to produce an executable file until you've corrected the error and provided a valid value. VC++ flags a warning but produces an executable if you've set error level to 3 and not checked 'warnings as errors'. I always compile my code at error level 4 and 'warnings as errors'.

The CBClass constructor expects a first parameter of type constsOfInterestToThisClass. This may be either bConstantOfInterestToThisClass1 or bConstantOfInterestToThisClass2 or a variable of type constsOfInterestToThisClass. The compiler will let you define a variable of type constsOfInterestToThisClass but will only let you assign values from the enum values you define.

CBClass::constsOfInterestToThisClass var;

var = CBClass::bConstantOfInterestToThisClass1;  // OK

var = 47;  // Error

Another issue

From reading the foregoing it's tempting to conclude that the final default: case in CBClass::DoSomething() is superfluous. You might even have thought I left it in by mistake. After all, if you've used an enum correctly the default: should never occur. That's true today. But what if you add a new enum constant sometime down the track and forget to add code to the DoSomething() function to handle it? If your switch statement silently ignores enum values it doesn't know about you run the risk of incurring all kinds of unexpected (and difficult to trace) behaviour. Leaving the default: case in place greatly increases your chances of catching such oversights during program development and testing.

Casts

As one or two readers have pointed out it's possible to defeat the whole point of this article by using casts.  For example one could code my error example from above thusly:

CBClass::constsOfInterestToThisClass var;

var = CBClass::bConstantOfInterestToThisClass1;  // OK

var = (CBClass::constsOfInterestToThisClass) 47; // Compiles

and the compiler will happily compile your code.  Of course it won't run as you expected but if you left the default: code in the switch statement at least you'll get an exception at runtime and hopefully during program testing.  What you're doing here of course is saying to the compiler, in effect, 'you know and I know that 47 isn't a valid constant here but I know better than you do so just go ahead and compile it for me'.  Once you've asserted your superior knowledge to the compiler all bets are off.

Interestingly, the compiler considers some casts to be so extreme that it still won't compile them without an intermediate step.  Ie, cast something to something else, then cast that something else to the final type.

Conclusion

The compiler will do a lot of error checking for you at compile time, if you let it. Using enum's rather than const's helps the compiler find places in your code where you've made incorrect assumptions. The compiler's a lot more thorough than most of us are when it comes to checking datatypes! <!------------------------------- That's it! --------------------------->

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Rob Manderson

United States United States
I've been programming for 35 years - started in machine language on the National Semiconductor SC/MP chip, moved via the 8080 to the Z80 - graduated through HP Rocky Mountain Basic and HPL - then to C and C++ and now C#.

I used (30 or so years ago when I worked for Hewlett Packard) to repair HP Oscilloscopes and Spectrum Analysers - for a while there I was the one repairing DC to daylight SpecAns in the Asia Pacific area.

Afterward I was the fourth team member added to the Australia Post EPOS project at Unisys Australia. We grew to become an A$400 million project. I wrote a few device drivers for the project under Microsoft OS/2 v 1.3 - did hardware qualification and was part of the rollout team dealing directly with the customer.

Born and bred in Melbourne Australia, now living in Scottsdale Arizona USA, became a US Citizen on September 29th, 2006.

I work for a medical insurance broker, learning how to create ASP.NET websites in VB.Net and C#. It's all good.

Oh, I'm also a Kentucky Colonel. http://www.kycolonels.org

Comments and Discussions

 
GeneralUndeclared Identifier Error Pin
LazyKancha10-Apr-06 19:51
memberLazyKancha10-Apr-06 19:51 
GeneralRe: Undeclared Identifier Error Pin
Vibhash Jha3-May-06 2:50
memberVibhash Jha3-May-06 2:50 
QuestionWhat if it must be specified at runtime ? Pin
cedric moonen6-Apr-05 9:46
membercedric moonen6-Apr-05 9:46 
QuestionWhat am I doing wrong? Pin
Anonymous23-Nov-04 22:56
sussAnonymous23-Nov-04 22:56 
AnswerRe: What am I doing wrong? Pin
Vibhash Jha3-May-06 2:41
memberVibhash Jha3-May-06 2:41 
GeneralConst still needed Pin
Crawfis29-Oct-03 10:07
memberCrawfis29-Oct-03 10:07 
GeneralAnother good reason for noy using consts Pin
xprsg21-Oct-03 15:17
memberxprsg21-Oct-03 15:17 
GeneralToo bad enums are integer only Pin
Sébastien Lorion11-Oct-03 21:46
memberSébastien Lorion11-Oct-03 21:46 
GeneralRe: Too bad enums are integer only Pin
Rob Manderson12-Oct-03 1:36
editorRob Manderson12-Oct-03 1:36 
GeneralRe: Too bad enums are integer only Pin
Sébastien Lorion12-Oct-03 10:22
memberSébastien Lorion12-Oct-03 10:22 
GeneralI find enums very useful Pin
Damir Valiulin10-Oct-03 7:44
memberDamir Valiulin10-Oct-03 7:44 
GeneralRe: I find enums very useful Pin
Rob Manderson12-Oct-03 1:37
editorRob Manderson12-Oct-03 1:37 
QuestionTypo ? Pin
Nick Seng8-Oct-03 17:30
memberNick Seng8-Oct-03 17:30 
AnswerRe: Typo ? Pin
Rob Manderson8-Oct-03 19:59
editorRob Manderson8-Oct-03 19:59 
GeneralRe: Typo ? Pin
Nick Seng8-Oct-03 20:45
memberNick Seng8-Oct-03 20:45 
GeneralRe: Typo ? Pin
Rob Manderson9-Oct-03 1:41
editorRob Manderson9-Oct-03 1:41 
GeneralNeed help about vc++ Pin
Zakaria khan7-Oct-03 4:52
memberZakaria khan7-Oct-03 4:52 
GeneralRe: Need help about vc++ Pin
jhwurmbach7-Oct-03 5:19
memberjhwurmbach7-Oct-03 5:19 
GeneralNeed Help Pin
Mohsin Rizwan6-Oct-03 12:42
memberMohsin Rizwan6-Oct-03 12:42 
GeneralRe: Need Help Pin
Jubjub6-Oct-03 22:42
memberJubjub6-Oct-03 22:42 
GeneralRange of an enumerator Pin
Gavin Greig6-Oct-03 2:50
memberGavin Greig6-Oct-03 2:50 
GeneralCBClass::constsOfInterestToThisClass var; Pin
Anonymous12-Jul-03 7:37
sussAnonymous12-Jul-03 7:37 

// How could you declare this without errors?
constsOfInterestToThisClass var;

// Should be: ?!
CBClass::constsOfInterestToThisClass var;



Greetings
GeneralRe: CBClass::constsOfInterestToThisClass var; Pin
Rob Manderson13-Jul-03 12:41
editorRob Manderson13-Jul-03 12:41 
GeneralWhat's the size of... Pin
Kochise9-Jul-03 0:46
memberKochise9-Jul-03 0:46 
GeneralI think... Pin
Brian Delahunty3-Jul-03 7:07
memberBrian Delahunty3-Jul-03 7:07 
GeneralRe: I think... Pin
souldog1-Aug-03 17:08
membersouldog1-Aug-03 17:08 
Questionerrr.. virtual functions? Pin
souldog25-Jun-03 1:15
membersouldog25-Jun-03 1:15 
AnswerRe: errr.. virtual functions? Pin
jfrancik25-Jun-03 12:07
memberjfrancik25-Jun-03 12:07 
GeneralRe: errr.. virtual functions? Pin
souldog25-Jun-03 12:21
membersouldog25-Jun-03 12:21 
GeneralRe: errr.. virtual functions? Pin
jfrancik25-Jun-03 12:41
memberjfrancik25-Jun-03 12:41 
GeneralStatic consts are not so bad... Pin
Kandjar24-Jun-03 12:17
memberKandjar24-Jun-03 12:17 
GeneralAnother reason for default case Pin
David Max24-Jun-03 7:13
memberDavid Max24-Jun-03 7:13 
GeneralYou've got it right! Pin
Gary Wheeler18-Jun-03 5:15
memberGary Wheeler18-Jun-03 5:15 
GeneralRe: You've got it right! Pin
UltraJoe24-Jun-03 4:46
memberUltraJoe24-Jun-03 4:46 
QuestionNot equivalent? Pin
Anonymous18-Jun-03 0:10
sussAnonymous18-Jun-03 0:10 
AnswerRe: Not equivalent? Pin
Rob Manderson18-Jun-03 0:50
editorRob Manderson18-Jun-03 0:50 
GeneralRe: this is still unclear... Pin
Rob Manderson17-Jun-03 23:58
editorRob Manderson17-Jun-03 23:58 
GeneralRe: this is still unclear... Pin
Rob Manderson18-Jun-03 0:58
editorRob Manderson18-Jun-03 0:58 
GeneralRe: this is still unclear... Pin
Rob Manderson18-Jun-03 1:16
editorRob Manderson18-Jun-03 1:16 
General[Message Deleted] Pin
Nice Life18-Jun-03 1:23
memberNice Life18-Jun-03 1:23 
GeneralRe: this is still unclear... Pin
Rob Manderson18-Jun-03 1:26
editorRob Manderson18-Jun-03 1:26 
GeneralRe: this is still unclear... Pin
Brian Delahunty3-Jul-03 7:02
memberBrian Delahunty3-Jul-03 7:02 
GeneralRe: this is still unclear... Pin
Kevin McFarlane24-Jun-03 1:25
memberKevin McFarlane24-Jun-03 1:25 
GeneralSome points Pin
Daniel Andersson17-Jun-03 23:02
memberDaniel Andersson17-Jun-03 23:02 
GeneralRe: Some points Pin
Rob Manderson17-Jun-03 23:16
editorRob Manderson17-Jun-03 23:16 
QuestionHow I'd have coded it... Pin
George17-Jun-03 1:33
memberGeorge17-Jun-03 1:33 
AnswerRe: How I'd have coded it... Pin
LikeItMatters17-Jun-03 2:46
sussLikeItMatters17-Jun-03 2:46 
GeneralRe: How I'd have coded it... Pin
Rob Manderson17-Jun-03 23:51
editorRob Manderson17-Jun-03 23:51 
AnswerRe: How I'd have coded it... Pin
peterchen17-Jun-03 3:20
memberpeterchen17-Jun-03 3:20 
GeneralRe: How I'd have coded it... Pin
George17-Jun-03 3:45
memberGeorge17-Jun-03 3:45 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.150428.2 | Last Updated 6 Oct 2003
Article Copyright 2003 by Rob Manderson
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid