Understanding how to correctly treat c++ class constants

37,586

Solution 1

If you want the constants specific to the class and also want them to be useful somewhere else as you said, possibly outside the class, then define them as static member data in the public section of the class:

//.h file
class MyClass 
{
 public:
   //constants declarations
   static const int MYINT;
   static const std::string MYSTR;
};

//.cpp file
//constants definitions 
const int MyClass::MYINT = 12;
const std::string MyClass::MYSTR = std::string("Hello");

Usage (or access):

std::cout << MyClass::MYINT << std::endl;
std::cout << MyClass::MYSTR << std::endl;

Output:

12
Hello

Online Demo: http://www.ideone.com/2xJsy


You can also use enum if you want to define many integral constants and all of them are somehow related, for example this:

class shirt
{
 public:
   //constants declarations
   enum shirt_size
   {
        small, 
        medium,
        large,
        extra_large
   };
};

But if the integral constants are not related, then it wouldn't make much sense to define them as enum, in my opinion.

Solution 2

There is no "best" solution as of course that is a very subjective term.

Considering that you mention the constants being used somewhere else, we can say that they should be declared in either the protected (if they are to be used exclusively by derived classes) or more likely the public section of the class.

Constants that are not of integer type should be defined as static const members (but you will have to be careful of the order of static initialization if there are any other static objects that refer to these constants).

Constants of integer type can either be declared as static const int or as enums, as you already mention. The discriminating factor here is whether two or more constants can be logically grouped together.

For example, this is probably a good idea:

class MyClass {
    public:
        enum {
            Color_Red,
            Color_Green,
            Color_Blue,
        };
};

While this is not:

class MyClass {
    public:
        enum {
            Color_Red,
            Vehicle_Car,
        };
};
Share:
37,586

Related videos on Youtube

Andry
Author by

Andry

Made in Italy, with some parts from Japan, now living and working in Denmark. Basically just a Software Engineer :) Main interests I really like programming and developing stuff. My main focus in web application development and testing. Among the technologies I am passionate about, you can find: ASP.NET, .NET, C#, VB.NET, WCF, C/C++ (all hail Bjarne), Boost C++ Library, Java, Javascript + dialects (Typescript, etc.), HTML5, CSS + dialects (SASS, LESS, etc.). I have a lot of interests in Mathematics as well. Among engineering technologies, I really like working with: Wolfram Mathematica, Wolfram Language, Matlab. I also like creating graphics, animations and presentation using the most popular applications in the Adobe families (I saw Flash growing since when it was still a baby, 5.0, and it was still Macromedia, RIP). (Human) Languages I like travelling a lot, and the best part of travelling is experiencing new languages, new sounds new people and culture. I actually love Asia. I lived in Japan and worked there. Made also a lot of friends and gonna return there soon (I hope). I can speak Italian, English, Japanese and still learning this fancy language called Danish. Sports I also like sports. I practiced many but now I almost focused my entire life on swimming and open water swimming. Now I made a full transition to diving (no scuba!). Other I also like photography, reading lots of books, food (strange food) and music. But most of all I like sharing knowledge with other people. More knowledge in the world means a better world! That's why I am #SOreadytohelp!

Updated on April 12, 2020

Comments

  • Andry
    Andry about 4 years

    Consider the following:

    namespace MyNamespace{
    class MyClass {
    public:
       // Public area
    private:
       // Private area
    protected:
       // Protected area
    }; /* Class */
    } /* Namespace */
    

    And consider that I would like to define a constant which is specific for my class. I usually do the following:

    namespace MyNamespace{
    // Constants
    const int MYINT = 12;
    const std::string MYSTR = std::string("Hello");
    // Class definition
    class MyClass {
    public:
       // Public area
    private:
       // Private area
    protected:
       // Protected area
    }; /* Class */
    } /* Namespace */
    

    In this way I can get my variable in this way (somewhere in my code):

    MyNamespace::MYINT;
    MyNamespace::MYSTR;
    

    Is this a good practice? Considering that constants can be treated in several ways (for example numeric constants are often treated using enum), what is the best approach to define a constant (related to a class, but that can be also useful somewhere else)?

    Thankyou

  • Waihon Yew
    Waihon Yew about 13 years
    @Andry: No, you cannot. You need to declare them in the header and define them in a separate .cpp file.
  • Nawaz
    Nawaz about 13 years
    @Andry: No, you cannot. If you do, you'll get multiple definition error if you include the header file to many cpp file. So the best approach is : the definition should be in .cpp file, as I edited my answer.
  • David Rodríguez - dribeas
    David Rodríguez - dribeas about 13 years
    @Andry: Can I declare and defined them in header only? Short answer is no, but there is a longer answer... if the constant is of integral type, you can get away with just declaring and assigning the value in the header. The detail is that you can only do this if the integral constant is not used, where used basically means used as an lvalue. I.e. you can use it as a compile time constant or in any circumstance where an rvalue suffices: int x = 1 + type::constant;, but not where an lvalue is required: int const & k = type::constant;.
  • David Rodríguez - dribeas
    David Rodríguez - dribeas about 13 years
    @Nawaz: For integral constants, it is usually better to provide the value in the declaration, instead of the definition. That enables the compiler to use that value as a compile time constant. struct test { static const int a = 5; static const int b; }; int const test::a; int const test::b = 7; int array[ test::a ]; /*ok*/ int error[test::b]; /*not ok*/
  • Nawaz
    Nawaz about 13 years
    @David Rodríguez: Nice. I do that usually. I didn't do that now, because there is const std::string also, which I can't initialize in the class itself. So for consistency, I did that. :-)

Related