Typically, the way I'd define a true global constant (lets say, pi) would be to place an extern const in a header file, and define the constant in a .cpp file:
constants.h:
extern const pi;
constants.cpp:
#include "constants.h"
#include <cmath>
const pi=std::acos(-1.0);
This works great for true constants such as pi. However, I am looking for a best practice when it comes to defining a "constant" in that it will remain constant from program run to program run, but may change, depending on an input file. An example of this would be the gravitational constant, which is dependent on the units used. g is defined in the input file, and I would like it to be a global value that any object can use. I've always heard it is bad practice to have non-constant globals, so currently I have g stored in a system object, which is then passed on to all of the objects it generates. However this seems a bit clunky and hard to maintain as the number of objects grow.
Thoughts?
It all depends on your application size. If you are truly absolutely sure that a particular constant will have a single value shared by all threads and branches in your code for a single run, and that is unlikely to change in the future, then a global variable matches the intended semantics most closely, so it's best to just use that. It's also something that's trivial to refactor later on if needed, especially if you use distinctive prefixes for globals (such as g_
) so that they never clash with locals - which is a good idea in general.
In general, I prefer to stick to YAGNI, and don't try to blindly placate various coding style guides. Instead, I first look if their rationale applies to a particular case (if a coding style guide doesn't have a rationale, it is a bad one), and if it clearly doesn't, then there is no reason to apply that guide to that case.
I can understand the predicament you're in, but I am afraid that you are unfortunately not doing this right.
The units should not affect the program, if you try to handle multiple different units in the heart of your program, you're going to get hurt badly.
Conceptually, you should do something like this:
Parse Input
|
Convert into SI metric
|
Run Program
|
Convert into original metric
|
Produce Output
This ensure that your program is nicely isolated from the various metrics that exist. Thus if one day you somehow add support to the French metric system of the 16th century, you'll just add to configure the Convert
steps (Adapters) correctly, and perhaps a bit of the input/output (to recognize them and print them correctly), but the heart of the program, ie the computation unit, would remain unaffected by the new functionality.
Now, if you are to use a constant that is not so constant (for example the acceleration of gravity on earth which depends on the latitude, longitude and altitude), then you can simply pass it as arguments, grouped with the other constants.
class Constants
{
public:
Constants(double g, ....);
double g() const;
/// ...
private:
double mG;
/// ...
};
This could be made a Singleton
, but that goes against the (controversed) Dependency Injection idiom. Personally I stray away from Singleton
as much as I can, I usually use some Context
class that I pass in each method, makes it much easier to test the methods independently from one another.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With