Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't C++ cast to const when a const method is public and the non-const one is protected?

Tags:

c++

constants

I created a class with two get methods, one const and one non-const. The const method is public, so users can query the vector. The non-const method is protected, so I can use it to modify the data I need.

When I try to use the class, however, and call the get method, the compiler complains that the non-const method is protected. Instead, I have to use const_cast to cast the object to const, so I can get instead the public method.

Is there a way to solve this? Why wouldn't the compiler do the cast itself, since there is a public method? If I remove the protected version and just leave the const one, it works fine, so it does do the cast in this situation. Casting to const is always safe. It's removing constness that is a problem.

like image 236
Kian Avatar asked Dec 26 '12 18:12

Kian


2 Answers

Member access control is the very last thing that occurs when calling a member function. It happens after name lookup, template argument deduction, overload resolution, and so on. The reason why it is done last is because it was decided that changing the access control for a member should not suddenly change the execution of client code.

Imagine access was checked before overload resolution, and you used a library and a certain member function in that library. Then the library authors made the function private. Suddenly, your code starts using a different overload and behaves in a completely different way. The library authors probably intended that anybody using that overload of the function should stop using it, but they didn't intend to change everybody's code. However, as the standard is actually defined, your code would now start giving you an error for using a private member, rather than behave differently.

The solution is to simply change the name of your protected member function so that it isn't considered.

like image 77
Joseph Mansfield Avatar answered Nov 15 '22 18:11

Joseph Mansfield


The compiler considers accessibility after it decides what member function it wants to call. That is, protected and private functions are still visible, even though they aren't accessible.

Why? One reason is that if you made inaccessible functions ignored by overload resolution, you could change what function is called simply by changing its accessibility. With the current rules, you can only cause compiling code to fail to compile, or cause code that currently doesn't work to compile, or change something with no effect on the meaning of the code. You cannot change access specifiers and silently cause a different function to be called.

As a contrived example, here's a pretty terrible class interface:

public:
    // Returns the amount of change tendered for this transaction.
    MoneyAmount change() const;

private:
    // Account for a change of currency. Charges standard moneychanger's fee.
    MoneyAmount change(Currency toCurrency = Currency::USD);

If inaccessible functions were removed from overload resolution, client code could call change() just fine. And if later the second change(Currency) function was made public and the first one deleted, that code would suddenly silently call another function with an entirely different purpose. The current rules prevent a change of access specifier from changing the behavior of a compiling program.

like image 37
John Calsbeek Avatar answered Nov 15 '22 16:11

John Calsbeek