In case I have two methods - one public, one protected that return the reference to same member, I get following compilation error:
'Server::getManager': cannot access protected member declared in class 'Server'
When I comment out protected function, code works. Could you please advise why this is happening? Why the compiler cannot find the public function to same member?
class Manager
{
};
class Server
{
public:
const Manager & getManager() const { return m_man; }
protected:
Manager & getManager() { return m_man; } // <-- after removing this method I get no compilation error
private:
Manager m_man;
};
int main()
{
Server s;
const Manager& m = s.getManager();
return 0;
}
Why the compiler cannot find the public function to same member?
That's not the issue. The compiler finds both functions and performs overload resolution to determine which is the best viable candidate. The two candidates are:
Manager& getManager() // protected
Manager const& getManager() const // public
For member functions, there is an implicit first object parameter that is the instance of the class itself. In this case, the two functions become:
getManager(Server& ) // protected
getManager(Server const& ) // public
We're invoking it on an object (s
) that is not const
. Both candidates are viable, but the public
candidate takes a reference to a more cv-qualified object than the protected
candidate - so it's less preferred. The standardese is in [over.ics.rank]:
Standard conversion sequence S1 is a better conversion sequence than standard conversion sequence S2 if
— S1 and S2 are reference bindings (8.5.3), and the types to which the references refer are the same type except for top-level cv-qualifiers, and the type to which the reference initialized by S2 refers is more cv-qualified than the type to which the reference initialized by S1 refers.
As a result, the protected
candidate is preferred - so that's the one that's called.
Unfortunately, it's protected
, so calling it is ill-formed. The access control is checked after overload resolution. So you'll have to restructure your program somehow. You could simply cast s
to const
:
const Manager& m = const_cast<Server const&>(s).getManager();
This would make the protected
candidate non-viable.