简体   繁体   中英

How change global const variables to variables that can be assigned via a function

I have some code which contains const gobal variables; The code needs to be extended to support parametrization, ie, based on a parameter some of the variables have to change. It happens that some of the variables that need to change are global const s.

file1.h

const double a = 2;
const double b = 3;

file.h is inherited by multiple different .cc which use a and b .


After reading online I got introduced to the extern keyword. So following some guidelines I did the following.

1) Declared a and b as externs in the header file: file.h:

extern const double a;
extern const double b;

2) Created a file.cc file where I use a function to assign values to a and b :

void setConsts(double parameter){
    /* request the linkage */
    extern const double a;
    extern const double b;

    if (parameter == 9){
        a = 2 * 9;
        b = 3 * 9;
    }
    else if (parameter == 10){
        a = 2 * 10;
        b = 3 * 10;
    }
    else{
        std::cout<<"parameter not supported"<<std::endl;

Now probably because a and b are const s I receive:

error: read-only variable is not assignable


What is the nice and the elegant way of changing global const s into global variables which can be defined via a function, but still ensure that they will not be changed during run-time?

You cannot write to const variables. That's the whole point of them being const in the first place.

If you really need them to be non- const , then remove the "const" keyword from them and recompile your application.

Note: using const_cast will not work and will result in undefined behaviour (don't go there) since the objects are initially const. So don't even consider that (and btw a "C style cast" is also a const cast).

Step 1: Consider not using global variables. Instead pass values into the functions/classes that need them.

Step 2: Go to step 1 again.

Step 3: Ok, fine. If you really want globals... Try encapsulating them behind accessor functions. You could have something like GetGlobalA() and GetGlobalB() that all the code in your program can access. Then have an InitializeGlobals() which is obviously only used once during startup or wherever it is that these values need to be set. The variables themselves can simply be static ones inside a code file that nothing else has direct access to other than the functions I described (or if you make this all static on a class, then the variables are private statics of it).

If I understand you correctly, you want to initialize const variable based on some parameter (either compile-time or run-time). Note that const variables can be initialized by runtime expression.

double getParameter()
{
    //obtain parameter and return it
    return 9;
}

double getValueOfA(double param)
{
     if (param==9)
         return 2*9;
     if (param==10)
         return 2*10;
     else{
      throw(std::runtime_error("parameter value not supported"));
     }
}

double getValueOfB(double param)
{
     if (param==9)
         return 3*9;
     if (param==10)
         return 3*10;
     else{
      throw(std::runtime_error("parameter value not supported"));
     }

}

 const double a=getValueOfA(getParameter());

 const double b=getValueOfB(getParameter());

You cannot change the constants. If you want to set them from a parameter, constants are not what you are looking for. Once they are initialized, they cannot be changed.

I think that a good solution will be writing a simple class with privated variables a and b , with only getters to get them and a method to set them from a parameter. Then, add a global instance of this class and use it as you wish to. This way, user won't be able to change a and b directly, as they are privatized and you can decide, when user can set them and when he can't. As an example:

class optionsClass {
public:
    optionsClass():parametersSet(false) {};
    double getA(void) const {return a;}
    double getB(void) const {return b;}
    setParameter(double parameter) {
        if(!parametersSet) {compute a and b here; parametersSet = true;}
    }
private:
    bool parametersSet; double a, b;
}

a and b in this example also couldn't be const, by the way. A standard constructor is called for these variables and they are autocratically set to 0.

Wrap your variables in a class and use constructor to init them. You can also use singleton and design only getter so that you can never change them.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM