Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Where to declare/define class scope constants in C++?

I'm curious about the benefits/detriments of different constant declaration and definition options in C++. For the longest time, I've just been declaring them at the top of the header file before the class definition:

//.h const int MyConst = 10; const string MyStrConst = "String"; class MyClass { ... }; 

While this pollutes the global namespace (which I know is a bad thing, but have never found a laundry list of reasons why it is bad), the constants will still be scoped to individual translation units, so files that don't include this header won't have access to these constants. But you can get name collisions if other classes define a constant of the same name, which is arguably not a bad thing as it may be a good indication of an area that could be refactored.

Recently, I decided that it would be better to declare class specific constants inside of the class definition itself:

//.h class MyClass {     public:          static const int MyConst = 10; ...     private:          static const string MyStrConst; ... }; //.cpp const string MyClass::MyStrConst = "String"; 

The visibility of the constant would be adjusted depending on whether the constant is used only internally to the class or is needed for other objects that use the class. This is what I'm thinking is the best option right now, mainly because you can keep internal class constants private to the class and any other classes using the public constants would have a more detailed reference to the source of the constant (e.g. MyClass::MyConst). It also won't pollute the global namespace. Though it does have the detriment of requiring non-integral initialization in the cpp file.

I've also considered moving the constants into their own header file and wrapping them in a namespace in case some other class needs the constants, but not the whole class definition.

Just looking for opinions and possibly other options I hadn't considered yet.

like image 461
bsruth Avatar asked Jan 11 '10 17:01

bsruth


People also ask

Where do you declare class constants?

Class constants can be useful if you need to define some constant data within a class. A class constant is declared inside a class with the const keyword. Class constants are case-sensitive. However, it is recommended to name the constants in all uppercase letters.

How do we declare constants in C?

The const keyword Variables can be declared as constants by using the “const” keyword before the datatype of the variable. The constant variables can be initialized once only. The default value of constant variables are zero.

How do you define a constant in a header file?

You need to do: to make a constant pointer, so that the rule will apply to it. Also note that this is one reason I prefer to consistently put const after the type: int const instead of const int . I also put the * next to the variable: i.e. int *ptr; instead of int* ptr; (compare also this discussion).

How do you declare a constant in a class in C++?

Const member functions in C++ Constant member functions are those functions which are denied permission to change the values of the data members of their class. To make a member function constant, the keyword “const” is appended to the function prototype and also to the function definition header.


2 Answers

Your claim that declaring a non-integral constant as a static class member "have the detriment of requiring non-integral initialization in the cpp file" is not exactly solid, so to say. It does require a definition in cpp file, but it is not a "detriment", it is a matter of your intent. Namespace-level const object in C++ has internal linkage by default, meaning that in your original variant the declaration

const string MyStrConst = "String";  

is equivalent to

static const string MyStrConst = "String";  

i.e. it will define an independent MyStrConst object in every translation unit into which this header file is included. Are you aware of this? Was this your intent or not?

In any case, if you don't specifically need a separate object in every translation unit, the declaration of MyStrConst constant in your original example is not a good practice. Normally, you'd only put a non-defining declaration in the header file

extern const string MyStrConst;  

and provide a definition in the cpp file

const string MyStrConst = "String"; 

thus making sure that the entire program uses the same constant object. In other words, when it comes to non-integral constants, a normal practice is to define them in cpp file. So, regardless of how you declare it (in the class or out) you will normally always have to deal with the "detriment" of having to define it in cpp file. Of course, as I said above, with namespace constants you can get away with what you have in your first variant, but that would be just an example of "lazy coding".

Anyway, I don't think there is a reason to over-complicate the issue: if the constant has an obvious "attachment" to the class, it should be declared as a class member.

P.S. Access specifiers (public, protected, private) don't control visibility of the name. They only control its accessibility. The name remains visible in any case.

like image 84
AnT Avatar answered Oct 21 '22 02:10

AnT


Pollution of the global namespace is bad because someone (e.g. the writer of a library you use) might want to use the name MyConst for another purpose. This can lead to severe problems (libraries that can't be used together etc.)

Your second solution is clearly the best if the constants are linked to a single class. If that isn't so easy (think of physical or math constants without ties to a class in your program), the namespace solution is better than that. BTW: if you must be compatible to older C++ compilers, remember some of them can't use integral initialization in a header file - you must initialize in the C++ file or use the old enum trick in this case.

I think there are no better options for constants - at least can't think of one at the moment...

like image 31
hjhill Avatar answered Oct 21 '22 02:10

hjhill