Standard says in 8.3.5/3 that for the purposes of determining the function type any cv-qualifiers that directly qualify the parameter type are deleted. I.e. it literally says that a function declared as
void foo(int *const a);
has function type void (int *)
.
A pedantic person might argue that this is not conclusive enough to claim that the above declaration should match the definition like this one
void foo(int *a)
{
}
or that it should make the code with dual declaration (as in your example) ill-formed, since neither of these concepts are described in the standard in terms of function types.
I mean, we all know that these const
were intended to be ignored for all external purposes, but so far I was unable to find the wording in the standard that would conclusively state exactly that. Maybe I missed something.
Actually, in 13.1/3 it has a "Note" that says that function declarations with equivalent parameter declarations (as defined in 8.3.5) declare the same function. But it is just a note, it is non-normative, which suggests that somewhere in the standard there should be some normative text on the same issue.
In N3242 (the standard draft I have on hand), 13.3.1 paragraph 4 says
the type of the implicit object parameter is "lvalue reference to cv X” for [non-static member] functions declared without a
ref-qualifier or with the & ref-qualifier
this means that type of the implicit object argument, which occurs first, is an "lvalue reference to cv X
", where X
is the class, and cv
is the cv-qualification of the member variable (i.e. const or non-const). Then, overload resolution continues as normal.
To review the overload resolution process, first, both are listed as "candidate" functions as they are in the correct scope and have the correct name.
In the const
case, only the const
member function gets to the next step (called "viability"), so it's automatically the best choice. The non-const member function is not viable because you can't convert a const
reference into a non-const reference.
In the non-const case, both the const and non-const versions are viable, but the non-const one is "better" because of the fifth rule of 13.3.3.2 paragraph 3, quoted below.
Standard conversion sequence S1 is a better conversion sequence than
standard conversion sequence S2 if ...
S1 and S2 are reference bindings, 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.
Best Answer
Part of the problem which wasn't mentioned in other answers is that accessibility and visibility are independent concepts in C++. The
B& A::getMe()
private member is visible inmain
even if it isn't accessible. So in your calla.getMe()
there are two overloaded members to consider,B& A::getMe()
andB const& A::getMe() const
. Asa
is notconst
it is the private member which is selected. Then you get an error because it isn't accessible. If you hadn't the private non const member function, you would have the const member as the only possibility and it would have be called as a const member can be called on non const object.Note that if visibility was conditioned to accessibility, you could have other kind of confusing behavior: you refactor a member, putting a call to a private member outside the class. Now, the private member is no more accessible and so the call is to a different member which is public. That silent change of behavior can lead to bugs hard to track.
In conclusion: whatever are the rule of your language, never overload with different accessibility, it leads to confusion.