0

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).

Agrudge Amicus
  • 1,033
  • 7
  • 19
  • Because a non-`const` object will call the non-`const` version of the function if one is available. You have nicely described the expected behavior. What sort of justification are you looking for? – JaMiT Apr 26 '20 at 03:21
  • Does this answer your question? [Const and Non-Const Operator Overloading](https://stackoverflow.com/questions/19237411/const-and-non-const-operator-overloading) – JaMiT Apr 26 '20 at 03:57
  • Related, but not quite duplicate, questions: [Calling a const function from a non-const object](https://stackoverflow.com/questions/407100/calling-a-const-function-from-a-non-const-object) and [Calling a const function rather than its non-const version](https://stackoverflow.com/questions/7287065/calling-a-const-function-rather-than-its-non-const-version) – JaMiT Apr 26 '20 at 03:59
  • Because the C++ standard says so? – eesiraed Apr 26 '20 at 04:01
  • @BessieTheCow Can you give me any link for that? – Agrudge Amicus Apr 26 '20 at 04:06
  • @JaMiT https://stackoverflow.com/questions/19237411/const-and-non-const-operator-overloading doesn't answer about the reason. – Agrudge Amicus Apr 26 '20 at 04:08
  • I don't have a reference for that but I'm pretty sure the standard states somewhere that the non-const function is called for non-const objects. I don't know what kind of "reason" you're asking for because that's just the way it works. – eesiraed Apr 26 '20 at 04:11
  • @AgrudgeAmicus The reason is because that is the way the language works (and that *is* mentioned in the proposed duplicate). Sorry, but it's difficult to judge at what level you want an answer when you don 't respond to my comment asking you at what level you want an answer. (A response like "a link to the relevant part of the standard" would have sufficed.) Hmm... one way to differentiate your question from the proposed duplicate would be to add the [tag:language-lawyer] tag, although that might be more hardcore than you intend. Maybe just add to the question a request for a reference? – JaMiT Apr 26 '20 at 04:35

1 Answers1

1

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.

  1. Prefer to call 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.
  2. Prefer to call 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.
  3. Deem 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.

Peter
  • 35,646
  • 4
  • 32
  • 74