Reputation: 1103
In this code:
include<iostream>
using namespace std;
class A
{
public:
A(){} //constructor
void fun()
{
cout<<"in non-const fun"<<endl;
}
void fun() const
{
cout<<"in const fun"<<endl;
}
};
int main()
{
A obj;
A c_obj;
obj.fun()
c_obj.fun();
return 0;
}
If c_obj
were a const
object to class A
it would've called the const
version of fun()
.
A non-const
class object can call any of the versions of fun()
but they keep calling the non-const
version until and unless the non-const
version is deleted/commented - why?
Even if the order of definition is changed then also the behavior remained the same (just tried to check if it affects anything).
Upvotes: 0
Views: 105
Reputation: 36597
Let's say we have a class A
like that described by the OP (i.e. with a const
and non-const
version of the same member function, named A::fun() const
and A::fun()
respectively.
The difference between the two versions is that the specification of A::fun() const
function is that it will not logically change state the object it is called on, but that A::fun()
is permitted to.
If a expression/statement some_object.fun()
calls A::fun() const
then it will not change the logical state (i.e. value of non-static
members that are not specified as mutable
) of some_object
. (Assuming there is no undefined behaviour present).
Similarly, if the expression some_object.fun()
calls A::fun()
(the non-const
version), then the state of some_object
may be logically changed.
Now, we need to look at what the implementation (aka compiler) should do when it encounters an expression of the form some_object.fun()
. Since there are both A::fun() const
and A::fun()
, it is necessary to apply some criteria for the implementation to decide which one to call.
The first - simple - case is that some_object
is declared const
(or is a const
reference to an A
).
const A some_object;
some_object.fun();
This declaration expresses an intent, by the programmer, that logical state of some_object
will not be changed. The non-const
version of fun()
is permitted to change the state of some_object
, so it is never a valid match for some_object.fun()
- if the implementation chooses this, it must then issue a diagnostic (which, among other things, usually means that the code will not compile). All this means that A::fun() const
is the only permitted choice in this case.
The second case is that some_object
is NOT declared as const
.
A some_object;
some_object.fun();
The declaration expresses intent, by the programmer, to permit (or, at least, not disallow) changing the logical state of some_object
. Since A
has both a const
and a non-const
version of fun()
there are three possible choices that could (notionally) have been enshrined in the standard.
A::fun() const
over A::fun()
(the non-const
version). There is no harm in not changing an object for which change is permitted. However, this option also eliminates any circumstances in which the non-const
function A::fun()
would ever be called. There would therefore be no purpose in permitting a class to have both versions.A::fun()
over the A::fun() const
. There is no harm in this choice, since there is no harm in changing an object when change is permitted.A::fun()
and A::fun() const
to be equally good candidate. This introduces ambiguity for the compiler since there are two equally valid alternatives, and no reason to prefer one over the other, so a diagnostic is again required. As for option (1), this also means there are no circumstances in which the non-const
function would ever be called, so there is no point in permitting a class to have both versions.Option (2) above is what the standard requires. It means that there are defined circumstances in which each of A::fun()
and A::fun() const
may be called (a non-const
and a const
object respectively) and minimal uncertainty in the choice.
With both options (1) and (3), there is no point in the programmer providing both A::fun()
and A::fun() const
- or for the standard to even allow the programmer to provide both versions - since there are no circumstances in which the non-const
version would ever be called when given a statement or expression of the form some_object.fun()
. To introduce either option (1) or (3) there would need to be a (possibly complicated) set of additional clauses in the standard that specify when the non-const
version of the function should be called. While the C++ standardisation committee is notable for embracing obscure and complicated rules (possibly excessively) it appears they didn't in this case.
Upvotes: 1