简体   繁体   中英

const/non-const objects calling const/non-const functions

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

Let's say we have a class A like that described by the OP (ie 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 (ie 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM