Related
I have a Display class that uses SDL to write pixels to the screen. I'd like another class (Triangle) to be able to use this already existent class object, so I've been trying to pass the object by address.
It's sort of working, in the sense that it is actually calling the methods. However, I was getting a segmentation fault in the DrawPixel function. After checking gdb and checking what values are in the function, I figured out that the color_buffer array does not exist (note that when DrawPixel is called directly from the display class in main it works fine).
After a little more testing, I determined that window_width, window_height etc are not set in the Triangle's version of the Display object. But they do exist in the original Display object.
So I'm assuming that I am not properly passing in my object, but I'm uncertain how to fix this issue as I thought passing by address would work just fine. How can I pass an already existing/instantiated class to another class?
I've also tried putting color_buffer into public variables in case private was causing it, but that didn't help.
Example:
main.cpp
int main() {
Display display;
Triangle triangle(&display);
// This doesn't work
triangle.DrawTriangle(300, 500, 0xFFFFFF00);
// This does work
display.DrawPixel(300, 500, 0xFFFFFF00);
return 0;
}
triangle.hpp
class Triangle {
private:
Display* display;
public:
DrawTriangle(int x, int y, uint32_t color);
};
triangle.cpp
Triangle::Triangle(Display* display) {
display=display;
}
Triangle::DrawTriangle(int x, int y, uint32_t color) {
display->DrawPixel(x, y, color);
}
display.hpp
class Display {
private:
// SDL Stuff defined here
uint32_t* color_buffer;
int window_width = 1920;
int window_height = 1080;
public:
Display();
DrawPixel(int x, int y, uint32_t color);
};
display.cpp
Display::Display() {
// SDL Stuff declared
color_buffer = new uint32_t[window_width * window_height];
}
Display::DrawPixel(int x, int y, uint32_t color) {
// This is receiving the correct values, but doesn't allow me to access
// any index of color_buffer.
color_buffer[(y * window_width) + x] = color;
}
Triangle::Triangle(Display* display) {
display=display;
}
the display is not the member of your class.Use this->display = display instead
You have to use "this" in Triangle constructor. That should solve the problem.
Triangle(Display* display) {
this->display=display;
}
A couple of things to add to the answers above:
use a different naming convention for member variables - this way it is very easy to avoid typos. _display, m_display, Display_ (Clang style =) )
class members are private by default so if you are following convention where attributes are defined on top, there's no need to add private:
Some prefer references (e.g. Display&), mostly to save typing ->, since if `Display goes out of scope it will have the same hilarious effect as passing a pointer.
static analyzers look down on pointer arithmetic(due to possible out-of-bounds writes).
You can use std::array from header:
static constexpr int WIDTH = 1920;
static constexpr int HEIGHT = 1080;
std::array<uint32_t, WIDTH* HEIGHT> m_color_buffer{};
and then either use m_color_buffer[index] = color (no bounds checking, random memory gets written if you write out of bounds in release and normally an exception in debug), or use m_color_buffer.at(index) - slower but this way you get an exception in release mode, but the compiler may complain about the stack size, as the definition is essentially the same as uint32_t buffer[WIDTH*HEIGHT]. std::vector is a better alternative - it hides buffer allocation, manages memory (no need to delete) at expense of the 2 extra pointers for begin and the end of the vector.
The code example lacked a destructor. Every new should have an accompanying delete hence either add it or just switch to a standard library container to avoid the headache =)
Last but not least - both classes override constructors. Display also manages resources. What happens when you copy Display instances? Move them? It is a bit of a headache and leads to a bit of a boilerplate, but it is best to implement Rule of 5 members and avoid accidental surprises =)
PS. C++ is a beautiful language =)
Basically, I have two classes, Peg and Disk. (It's a Towers of Hanoi program) The files I have are Disk.h, Disk.cpp, Peg.h, Peg.cpp, and main.cpp. Not sure if that matters. Here's the disk class from Disk.h
#include <vector>
#include "gwindow.h"
#ifndef DISK_H
#define DISK_H
class Disk
{
private:
int xCoord; //x and y coords are for drawing in a gwindow
int yCoord;
int mHeight;
int mWidth;
COLOR mColor;
int mName; //helps me keep track of which is which
public:
Disk(); //default constructor
Disk(int x, int y, int heightIn, int widthIn, COLOR colorIn);
void setXY(int x, int y); //this is the one I'm having trouble with
int getHeight();
int getWidth();
int getX();
int getY();
COLOR getColor();
std::string diskColor();
void draw(GWindow &gw);
void nameDisk(int name); //yet this one is working?
int getName();
};
#endif
However, I'm having trouble with the setXY function. When I call it from main, it calls the function properly, changes the variable inside the scope of setXY, but the value doesn't persist outside the function. However, nameDisk works fine and is basically the same thing, except it is changing mName instead of xCoord and yCoord. Here is setXY:
void Disk::setXY(int x, int y)
{
xCoord = x;
yCoord= y;
}
and here is how I call it from main:
pegVec[2].getDisks()[0].setXY(690, 200);
I know this looks crazy, but basically pegVec is a vector of 3 peg objects. Each peg object has a function, getDisks(), which returns a vector of all the disks on that peg currently. So the line above is trying to perform setXY on the first peg on peg 2. Sorry if that's unclear, but I've tried making a new disk object and calling it on that and that didn't work either.
Here is getDisks, if it matters:
std::vector<Disk> Peg::getDisks()
{
return disksOn;
}
and disksOn is just a member variable of Peg:
std::vector<Disk> disksOn;
I think it might be a problem with how getDisks() works. I'm a noob, but I'm guessing that returning the vector disksOn makes a "copy" of it, kind of, which is what I am altering with my setXY function but which is not the same as the actual disksOn vector associated with the Peg object? I don't know if that makes sense.
What I've tried so far:
Making xCoord and yCoord public variables and updating them manually instead of making a setter function. This did not work.
I printed out the x and y values at every step. Inside setXY, the values were updated successfully, but when the function ended they went back to how they were.
I tried some mess with the const keyword, but I don't understand it and couldn't even get it to run.
Passing everything by reference/value
Making a new function in main which accepted a Disk vector as input, and using getDisks as input to that function. Didn't work, same problems.
Tested my other setter function, nameDisk, which works fine. It's essentially the same as setXY, which is why I think the problem is with getDisks.
Using pointers at various points (heh) throughout, but I wasn't sure the best way to do that. I was messing with it last night so I don't remember 100% but I think I tried to have getDisks return a pointer instead of the vector, and I don't think that worked, but it's more likely a problem with my syntax and how I used the pointer. I think that might work but I don't know how to shake it.
Help?
You're on the right track - somehow you're looking at a different objects than what you think you are. Using references is a good solution, but you may not have got the right one ;-)
Try:
// Return reference to the disks on the peg.
std::vector<Disk>& Peg::getDisks()
{
return disksOn;
}
The issue is that
std::vector<Disk> getDisks() { return disksOn; }
returns a completely new and separate temporary copy of disksOn rather than a reference to the original. So you're modifying a temporary copy which gets discarded at the end of the statement.
You need to use
std::vector<Disk> &getDisks() { return disksOn; } in order to return a reference to disksOn.
Although if you are going to return a reference to the vector member object you might as well make the object directly accessible as public because anyone can manipulate the vector at this point and get rid of the getDisks() function as it serves no purpose in terms of access protection.
Better design would be to give access to individual disks:
Disk &getDisk(int index) {
return disksOn[index];
}
const Disk &getDisk(int index) const {
return disksOn[index];
}
The idea behind not giving direct access to the vector is that you can later change the underlying container type if needed without changing the code outside of the Peg class.
The second version (const) is necessary for accessing const Disks of const Peg objects.
First of all let me prefix this question with the following points:
1) I have searched Stackexchange for this issue, most of the code presented was difficult enough for me to follow in order to warrant Asking a new Question/Opening a new Thread about this. The closest i could find was this Creating multiple class objects with the same name? c++ and unfortunately this is way past my scope of understanding
2) http://www.cplusplus.com/doc/tutorial/classes/ has not really discussed this or i have missed it.
Now that this is out of the way:
Rectangle Class code:
class Rectangle {
private:
int lineNumber;
float valueMax;
float valueMin;
public:
Rectangle(SCStudyInterfaceRef sc, int lineNumber, float valueMax, float valueMin);
int getLineNumber(); // member function of class
float getValueMax(); // member function of class Rectangle
float getValueMin(); // member function of class Rectangle
};
Rectangle::Rectangle(SCStudyInterfaceRef sc, int lineNumber0, float value1, float value2) {
lineNumber = lineNumber0;
int value2_greater_than_value1 = sc.FormattedEvaluate(value2, sc.BaseGraphValueFormat, GREATER_OPERATOR, value1, sc.BaseGraphValueFormat);
if (value2_greater_than_value1 == 1) {
valueMax = value2;
valueMin = value1;
} else {
valueMax = value1;
valueMin = value2;
}
}
int Rectangle::getLineNumber() {
return lineNumber;
}
float Rectangle::getValueMax() {
return valueMax;
}
float Rectangle::getValueMin() {
return valueMin;
}
And here is the more important part, this code is running pretty much in a loop and will repeat everytime a certain event triggers it:
bool xxx = Conditions here
if (xxx) {
// Draw new rectangle using plattforms code
code here
// Save rectangle information in the list:
Rectangle rect(sc, linenumbr + indexvalue, high, low);
(*p_LowRectanglesList).push_back(rect);
}
bool yyy = conditions here
if (Short) {
// Draw new rectangle using plattforms code
code here
// Save rectangle information in the list:
Rectangle rect(sc, linenumber + indexvalue, high, low);
(*p_HighRectanglesList).push_back(rect);
}
So the question is the following:
Since this is looped everytime an event triggers the second part of the code is going to be run, the bool condition is going to be checked, if its true its going to use plattform integrated code to draw a rectangle. Once it has drawn it this information is going to be passed to a new rectangle object/instance based on the Rectangle Class in the first part of the code using the: Rectangle rect(sc, linenumber + indexvalue, high, low); part and then save that information in a list which is in a different part of the code for now and irrelevant.
What exactly happens when there is a new Bool = True condition and the code gets executed after it has already been executed? Will the old rectangle object be simply replaced with a new rectangle object with the same name and using the new parameters (since they change on every instance due to the way the code is written)? Or are there now two objects of the Rectangle Class using the same name "rect" ?
It's technically speaking not even that important to me since the information of the parameters should be pushed into a list anyways using the (*p_HighRectanglesList).push_back(rect); part of the code
So TL;DR:
Does "rect" get destroyed/overwritten or are there now potentially limitless amounts of Rectangle Objects/Instances called "rect" floating around?
My Apologies for the wall of text but being a complete noob i thought it would be best to outline my thought process so that it will be easier for you to correct me on where I'm wrong.
Kind regards,
Orbital
Yes, rect is destroyed and recreated every loop. In C++, the scope of any variable declared in a block (in this case an if() statement) is limited to that block. Every time your program iterates, you get a new rect, and the old rect is gone.
To add, whenever you call NEW, you are basically allocating memory and creating Rectangle objects. NEW will allocate address to each instance. The pointer *rect will be pointing to the current memory address, and when you call rect with NEW again, now rect will be pointing to the new memory address the previous address becomes a NULL reference. However in C++ you have to worry about memory leaks unlike Java where you have a garbage collector.
Before you cringe at the duplicate title, the other question wasn't suited to what I ask here (IMO). So.
I am really wanting to use virtual functions in my application to make things a hundred times easier (isn't that what OOP is all about ;)). But I read somewhere they came at a performance cost, seeing nothing but the same old contrived hype of premature optimization, I decided to give it a quick whirl in a small benchmark test using:
CProfiler.cpp
#include "CProfiler.h"
CProfiler::CProfiler(void (*func)(void), unsigned int iterations) {
gettimeofday(&a, 0);
for (;iterations > 0; iterations --) {
func();
}
gettimeofday(&b, 0);
result = (b.tv_sec * (unsigned int)1e6 + b.tv_usec) - (a.tv_sec * (unsigned int)1e6 + a.tv_usec);
};
main.cpp
#include "CProfiler.h"
#include <iostream>
class CC {
protected:
int width, height, area;
};
class VCC {
protected:
int width, height, area;
public:
virtual void set_area () {}
};
class CS: public CC {
public:
void set_area () { area = width * height; }
};
class VCS: public VCC {
public:
void set_area () { area = width * height; }
};
void profileNonVirtual() {
CS *abc = new CS;
abc->set_area();
delete abc;
}
void profileVirtual() {
VCS *abc = new VCS;
abc->set_area();
delete abc;
}
int main() {
int iterations = 5000;
CProfiler prf2(&profileNonVirtual, iterations);
CProfiler prf(&profileVirtual, iterations);
std::cout << prf.result;
std::cout << "\n";
std::cout << prf2.result;
return 0;
}
At first I only did 100 and 10000 iterations, and the results were worrying: 4ms for non virtualised, and 250ms for the virtualised! I almost went "nooooooo" inside, but then I upped the iterations to around 500,000; to see the results become almost completely identical (maybe 5% slower without optimization flags enabled).
My question is, why was there such a significant change with a low amount of iterations compared to high amount? Was it purely because the virtual functions are hot in cache at that many iterations?
Disclaimer
I understand that my 'profiling' code is not perfect, but it, as it has, gives an estimate of things, which is all that matters at this level. Also I am asking these questions to learn, not to solely optimize my application.
I believe that your test case is too artificial to be of any great value.
First, inside your profiled function you dynamically allocate and deallocate an object as well as call a function, if you want to profile just the function call then you should do just that.
Second, you are not profiling a case where a virtual function call represents a viable alternative to a given problem. A virtual function call provides dynamic dispatch. You should try profiling a case such as where a virtual function call is used as an alternative to something using a switch-on-type anti-pattern.
Extending Charles' answer.
The problem here is that your loop is doing more than just testing the virtual call itself (the memory allocation probably dwarfs the virtual call overhead anyway), so his suggestion is to change the code so that only the virtual call is tested.
Here the benchmark function is template, because template may be inlined while call through function pointers are unlikely to.
template <typename Type>
double benchmark(Type const& t, size_t iterations)
{
timeval a, b;
gettimeofday(&a, 0);
for (;iterations > 0; --iterations) {
t.getArea();
}
gettimeofday(&b, 0);
return (b.tv_sec * (unsigned int)1e6 + b.tv_usec) -
(a.tv_sec * (unsigned int)1e6 + a.tv_usec);
}
Classes:
struct Regular
{
Regular(size_t w, size_t h): _width(w), _height(h) {}
size_t getArea() const;
size_t _width;
size_t _height;
};
// The following line in another translation unit
// to avoid inlining
size_t Regular::getArea() const { return _width * _height; }
struct Base
{
Base(size_t w, size_t h): _width(w), _height(h) {}
virtual size_t getArea() const = 0;
size_t _width;
size_t _height;
};
struct Derived: Base
{
Derived(size_t w, size_t h): Base(w, h) {}
virtual size_t getArea() const;
};
// The following two functions in another translation unit
// to avoid inlining
size_t Derived::getArea() const { return _width * _height; }
std::auto_ptr<Base> generateDerived()
{
return std::auto_ptr<Base>(new Derived(3,7));
}
And the measuring:
int main(int argc, char* argv[])
{
if (argc != 2) {
std::cerr << "Usage: %prog iterations\n";
return 1;
}
Regular regular(3, 7);
std::auto_ptr<Base> derived = generateDerived();
double regTime = benchmark<Regular>(regular, atoi(argv[1]));
double derTime = benchmark<Base>(*derived, atoi(argv[1]));
std::cout << "Regular: " << regTime << "\nDerived: " << derTime << "\n";
return 0;
}
Note: this tests the overhead of a virtual call in comparison to a regular function. The functionality is different (since you do not have runtime dispatch in the second case), but it's therefore a worst-case overhead.
EDIT:
Results of the run (gcc.3.4.2, -O2, SLES10 quadcore server) note: with the functions definitions in another translation unit, to prevent inlining
> ./test 5000000
Regular: 17041
Derived: 17194
Not really convincing.
With a small number of iterations there's a chance that your code is preempted with some other program running in parallel or swapping occurs or anything else operating system isolates your program from happens and you'll have the time it was suspended by the operating system included into your benchmark results. This is number one reason why you should run your code something like a dozen million times to measure anything more or less reliably.
There is a performance impact to calling a virtual function, because it does slightly more than calling a regular function. However, the impact is likely to be completely negligible in a real-world application -- even less so than appear in even the most finely crafted benchmarks.
In a real world application, the alternative to a virtual function is usually going to involve you hand-writing some similar system anyhow, because the behavior of calling a virtual function and calling a non-virtual function differs -- the former changes based on the runtime type of the invoking object. Your benchmark, even disregarding whatever flaws it has, doesn't measure equivalent behavior, only equivalent-ish syntax. If you were to institute a coding policy banning virtual functions you'd either have to write some potentially very roundabout or confusing code (which might be slower) or re-implement a similar kind of runtime dispatch system that the compiler is using to implement virtual function behavior (which is certainly going to be no faster than what the compiler does, in most cases).
I think that this kind of testing is pretty useless, in fact:
1) you are wasting time for profiling itself invoking gettimeofday();
2) you are not really testing virtual functions, and IMHO this is the worst thing.
Why? Because you use virtual functions to avoid writing things such as:
<pseudocode>
switch typeof(object) {
case ClassA: functionA(object);
case ClassB: functionB(object);
case ClassC: functionC(object);
}
</pseudocode>
in this code, you miss the "if... else" block so you don't really get the advantage of virtual functions. This is a scenario where they are always "loser" against non-virtual.
To do a proper profiling, I think you should add something like the code I've posted.
There could be several reasons for the difference in time.
your timing function isn't precise enough
the heap manager may influence the result, because sizeof(VCS) > sizeof(VS). What happens if you move the new / delete out of the loop?
Again, due to size differences, memory cache may indeed be part of the difference in time.
BUT: you should really compare similar functionality. When using virtual functions, you do so for a reason, which is calling a different member function dependent on the object's identity. If you need this functionality, and don't want to use virtual functions, you would have to implement it manually, be it using a function table or even a switch statement. This comes at a cost, too, and that's what you should compare against virtual functions.
When using too few iterations, there is a lot of noise in the measurement. The gettimeofday function is not going to be accurate enough to give you good measurements for only a handful of iterations, not to mention that it records total wall time (which includes time spent when preempted by other threads).
Bottom line, though, you shouldn't come up with some ridiculously convoluted design to avoid virtual functions. They really don't add much overhead. If you have incredibly performance critical code and you know that virtual functions make up most of the time, then perhaps it's something to worry about. In any practical application, though, virtual functions won't be what's making your application slow.
In my opinion, When there was less number of loops, may be there was no context switching, But when you increased the number of loops, then there are very strong chances that context switching takes place and that is dominating the reading. For example first program takes 1 sec and second program 3 secs, but if context switch takes 10 secs, then the difference is 13/11 instead of 3/1.
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.
A legitimate use of singletons!
A singleton class constants() with a method to set the units?
You can use a variant of your latter approach, make a "GlobalState" class that holds all those variables and pass that around to all objects:
struct GlobalState {
float get_x() const;
float get_y() const;
...
};
struct MyClass {
MyClass(GlobalState &s)
{
// get data from s here
... = s.get_x();
}
};
It avoids globals, if you don't like them, and it grows gracefully as more variables are needed.
It's bad to have globals which change value during the lifetime of the run.
A value that is set once upon startup (and remains "constant" thereafter) is a perfectly acceptable use for a global.
Why is your current solution going to be hard to maintain? You can split the object up into multiple classes as it grows (one object for simulation parameters such as your gravitational constant, one object for general configuration, and so on)
My typical idiom for programs with configurable items is to create a singleton class named "configuration". Inside configuration go things that might be read from parsed configuration files, the registry, environment variables, etc.
Generally I'm against making get() methods, but this is my major exception. You can't typically make your configuration items consts if they have to be read from somewhere at startup, but you can make them private and use const get() methods to make the client view of them const.
This actually brings to mind the C++ Template Metaprogramming book by Abrahams & Gurtovoy - Is there a better way to manage your data so that you don't get poor conversions from yards to meters or from volume to length, and maybe that class knows about gravity being a form acceleration.
Also you already have a nice example here, pi = the result of some function...
const pi=std::acos(-1.0);
So why not make gravity the result of some function, which just happens to read that from file?
const gravity=configGravity();
configGravity() {
// open some file
// read the data
// return result
}
The problem is that because the global is managed prior to main being called you cannot provide input into the function - what config file, what if the file is missing or doesn't have g in it.
So if you want error handling you need to go for a later initialization, singletons fit that better.
Let's spell out some specs. So, you want:
(1) the file holding the global info (gravity, etc.) to outlive your runs of the executable using them;
(2) the global info to be visible in all your units (source files);
(3) your program to not be allowed to change the global info, once read from the file;
Well,
(1) Suggests a wrapper around the global info whose constructor takes an ifstream or file name string reference (hence, the file must exist before the constructor is called and it will still be there after the destructor is invoked);
(2) Suggests a global variable of the wrapper. You may, additionally, make sure that that is the only instance of this wrapper, in which case you need to make it a singleton as was suggested. Then again, you may not need this (you may be okay with having multiple copies of the same info, as long as it is read-only info!).
(3) Suggests a const getter from the wrapper. So, a sample may look like this:
#include <iostream>
#include <string>
#include <fstream>
#include <cstdlib>//for EXIT_FAILURE
using namespace std;
class GlobalsFromFiles
{
public:
GlobalsFromFiles(const string& file_name)
{
//...process file:
std::ifstream ginfo_file(file_name.c_str());
if( !ginfo_file )
{
//throw SomeException(some_message);//not recommended to throw from constructors
//(definitely *NOT* from destructors)
//but you can... the problem would be: where do you place the catcher?
//so better just display an error message and exit
cerr<<"Uh-oh...file "<<file_name<<" not found"<<endl;
exit(EXIT_FAILURE);
}
//...read data...
ginfo_file>>gravity_;
//...
}
double g_(void) const
{
return gravity_;
}
private:
double gravity_;
};
GlobalsFromFiles Gs("globals.dat");
int main(void)
{
cout<<Gs.g_()<<endl;
return 0;
}
Globals aren't evil
Had to get that off my chest first :)
I'd stick the constants into a struct, and make a global instance of that:
struct Constants
{
double g;
// ...
};
extern Constants C = { ... };
double Grav(double m1, double m2, double r) { return C.g * m1 * m2 / (r*r); }
(Short names are ok, too, all scientists and engineers do that.....)
I've used the fact that local variables (i.e. members, parameters, function-locals, ..) take precedence over the global in a few cases as "apects for the poor":
You could easily change the method to
double Grav(double m1, double m2, double r, Constants const & C = ::C)
{ return C.g * m1 * m2 / (r*r); } // same code!
You could create an
struct AlternateUniverse
{
Constants C;
AlternateUniverse()
{
PostulateWildly(C); // initialize C to better values
double Grav(double m1, double m2, double r) { /* same code! */ }
}
}
The idea is to write code with least overhead in the default case, and preserving the implementation even if the universal constants should change.
Call Scope vs. Source Scope
Alternatively, if you/your devs are more into procedural rather thsn OO style, you could use call scope instead of source scope, with a global stack of values, roughly:
std::deque<Constants> g_constants;
void InAnAlternateUniverse()
{
PostulateWildly(C); //
g_constants.push_front(C);
CalculateCoreTemp();
g_constants.pop_front();
}
void CalculateCoreTemp()
{
Constants const & C= g_constants.front();
// ...
}
Everything in the call tree gets to use the "most current" constants. OYu can call the same tree of coutines - no matter how deeply nested - with an alternate set of constants. Of course it should be encapsulated better, made exception safe, and for multithreading you need thread local storage (so each thread gets it's own "stack")
Calculation vs. User Interface
We approach your original problem differently: All internal representation, all persistent data uses SI base units. Conversion takes place at input and output (e.g. even though the typical size is millimeter, it's always stored as meter).
I can't really compare, but worksd very well for us.
Dimensional Analysis
Other replies have at least hinted at Dimensional Analysis, such as the respective Boost Library. It can enforce dimensional correctness, and can automate the input / output conversions.