John Doe
John Doe

Reputation: 635

Best way to define class-scoped constant in C++

I need to use some constant value in a cpp file which is related to a class and won't be used outside of it.

I came up with several methods of doing this:

Method 1: static const in a .cpp file

static const int a = 100; // <<<

int Class::foo() const
{
    return a + 10;
}

int Class::bar() const
{
    return a - 10;
}

If I get this right, I can also omit the static keyword as the const automatically implies the internal linking in this context.
Please, correct me if I'm wrong.

Method 2: Anonymous namespace (C++11)

Basically same as the previous but:

namespace
{
    const int a = 100;
}

I believe this method is the preferred way to declare such scoped constants over the previous one in C++11.
Again, correct me if I'm wrong.

Method 3: static const in a .h file

class Class
{
public:
    int foo() const;
    int bar() const;
protected:
    static const int a = 100; // <<<
};

Method 4: non-static const in .h (C++11)

class Class
{
public:
    int foo() const;
    int bar() const;
protected:
    const int a = 100; // <<<
};

Or like this: const int a{100}. I think there is no difference for POD types.
And once again, correct me if I'm wrong.

Method 5: initializer list

class Class
{
public:
    Class() : a(100) {} // <<<
    int foo() const;
    int bar() const;
protected:
    const int a;
};

Summing up

I guess I must not use methods 1 and 2 as they will fail if I'll ever need to create a subclass.

Also, I think that the method 5 will be hard to maintain if there are many overloaded constructors.

Though the question may be considered opinion-based, mainly I'm trying to figure out the pros and cons of these methods, and probably there are some other possible solutions.

Upvotes: 4

Views: 1140

Answers (1)

Davis Herring
Davis Herring

Reputation: 39818

For ordinary global variables, const does imply static (but note that const char *f; isn’t const), so #1 with or without static is indeed the same. (This is really a misfeature, included as an emulation of constexpr inline many years before variables could have those.) #2 is also the same (preferred only in that types can also be declared in an anonymous namespace but cannot be declared static).

These are not intrinsically bad for derived classes: they restrict the constant to a source file, which can define methods for as few or as many classes as you like. You can also put them in .hpp files, although preferring a class member is reasonable.

For #3, note that the variable need not be initialized in the class definition. Doing so lets it be used in constant expressions in every file that includes the header, in which case the modern style (which supports non-integer variables) is to use constexpr.

#4 and #5 add a member to every class object and are best avoided—consider that they disable the default assignment operators.

Upvotes: 3

Related Questions