31

I have a legacy function that looks like this:

int Random() const
{
  return var_ ? 4 : 0;
}

and I need to call a function within that legacy code so that it now looks like this:

int Random() const
{
  return var_ ? newCall(4) : 0;
}

The problem is that I'm getting this error:

In member function 'virtual int Random() const':
class.cc:145: error: passing 'const int' as 'this' argument of 'int newCall(int)' discards qualifiers

Now I know in order to fix this error I can make my newCall() a const function. But then I have several funciton calls in newCall() that I have to make, so now I would have to make all of those function calls const. And so on and so forth until eventually I feel like half my program is going to be const.

My question: is there any way to call a function within Random() that isn't const? Or does anyone have any ideas on how to implement newCall() within Random() without making half my program const.

Thanks

-josh

justin
  • 104,054
  • 14
  • 179
  • 226
Grammin
  • 11,808
  • 22
  • 80
  • 138
  • You could make Random() non-const. – GWW Feb 15 '11 at 19:30
  • I would like to but Random() is legacy code that I can't really touch. – Grammin Feb 15 '11 at 19:31
  • 1
    Is that 4 chosen with an unbiased dice (thus making it really random). – Martin York Feb 15 '11 at 19:49
  • looking at the error message, I wander perhaps your problem is elsewhere? Note the "passing **const int** as 'this'". Sounds weird perhaps the 4 argument is interpreted as `this`? why? – davka Feb 15 '11 at 19:50
  • 1
    The question is not how many functions will have to be declared `const`, but whether those functions are actually `const`: do they modify any member of the object? If not, then mark them as const. – David Rodríguez - dribeas Feb 15 '11 at 19:57

7 Answers7

27
int Random() const
{
  return var_ ? const_cast<ClassType*>(this)->newCall(4) : 0;
}

But it's not a good idea. Avoid if it's possible!

Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • 2
    Like you said, if you really need to use `const_cast` to accomplish this, try to refactor your design. – thatWiseGuy Feb 17 '16 at 01:48
  • 1
    sometimes you can't help it.. the previous programmer over-designed, used all the fancy features in the language, and then left the company after his code gets too messy and unmaintainable.. – Zennichimaro Sep 28 '18 at 03:41
  • 1
    Finally the reasonable answer instead of 'you must not do that'... There are always situations when you should or even encouraged to. For example, what to do if you want to provide const interface method and use the same logic for the non-const implementation? For example, imagine tree walking logic. Should you copypaste it for writing const accessors and non-const accessors for all nodes? Or just create clean const and non-const wrappers for those tasks? – avtomaton Sep 17 '20 at 11:08
20

you should alter your program to use/declare const correctly...

one alternative is to use const_cast.

justin
  • 104,054
  • 14
  • 179
  • 226
  • 5
    Using const_cast incorrectly (which is what will happen hear) will lead to a complete disaster. – Martin York Feb 15 '11 at 19:47
  • 3
    Thanks for the advice, I ended up changing the functions below newCall() and newCall() to all be const, because I didn't want to use const incorrectly. – Grammin Feb 15 '11 at 20:07
  • 2
    @Grammin you're welcome. declaring it correctly has a lot of benefits. the most important (imo) is that it saves a ton of time in maintenance and readability. the compiler may quickly detect improper usage when the program changes. a side effect is that c++ starts to have so many consts written, that you think it would be nice if const were the default in some cases, and that a keyword was used to specify mutation instead :) – justin Feb 15 '11 at 20:37
  • 1
    There is another way, using a proxy. https://stackoverflow.com/questions/8325400/how-to-call-a-non-const-method-from-a-const-method – Janosimas May 05 '15 at 19:03
  • _"one alternative is to use const_cast."_... How should they use `const_cast`? – Vaillancourt Jun 27 '17 at 16:34
  • @AlexandreVaillancourt The point I make in my answer is that "you should alter your program to use/declare `const` correctly...". Using `const_cast` in the OP's scenario is an alternative which can be used to remove `const` from `this`. The implication I made 6 years ago (and today) is that you should not use `const_cast` to accomplish this because a) It will be confusing and incorrect and b) It can result in Undefined Behavior. Good examples of when to use `const_cast` is to introduce `const` or modify `const`, `volatile`, `__unaliged` qualifiers (in cases you know it is safe and legal). – justin Aug 03 '17 at 21:15
  • 1
    @AlexandreVaillancourt If you just want example usage, here it is: https://learn.microsoft.com/en-us/cpp/cpp/const-cast-operator -- Avoid erasing const where possible and understand what qualifies as UB. Certainly, `const_cast` is superior to C style casting -- when you (truly) need it. The cases when you need it should be quite rare when dealing with well written, modern APIs. I primarily use it when dealing with C APIs. Fortunately, I don't have to use it often. Finally, the line I don't recommend would look like this: `return var_ ? const_cast(this)->newCall(4) : 0;`. – justin Aug 03 '17 at 21:24
5
const_cast<MyClass *>(this)->newCall(4)

Only do this if you're certain newCall will not modify "this".

Erik
  • 88,732
  • 13
  • 198
  • 189
1

There are two possibilities here. First, newCall and ALL of its callees are in fact non-modifying functions. In that case you should absolutely go through and mark them all const. Both you and future code maintainers will thank you for making it much easier to read the code (speaking from personal experience here). Second, newCall DOES in fact mutate the state of your object (possibly via one of the functions it calls). In this case, you need to break API and make Random non-const to properly indicate to callers that it modifies the object state (if the modifications only affect physical constness and not logical constness you could use mutable attributes and propagate const).

Mark B
  • 95,107
  • 10
  • 109
  • 188
0

Without using const casts, could you try creating a new instance of the class in the Random() method?

Coffee on Mars
  • 988
  • 6
  • 21
0

The const qualifier asserts that the instance this of the class will be unchanged after the operation, something which the compiler cant automagically deduce.

const_cast could be used but its evil

Foo Bah
  • 25,660
  • 5
  • 55
  • 79
0

if it's really a random number generator, then the number generation code/state could likely be placed in a class-local static generator. this way, your object is not mutated and the method may remain const.

justin
  • 104,054
  • 14
  • 179
  • 226