3

Given the code below:

class A
{
public:
    A(): value( 0 ) {}

    int* get()
    {
        return &value;
    }

    const int& get() const
    {
        return value;
    }

private:
    int value;
};

int main()
{
    A a;
    const int& ref_value = a.get();
}

results in the following compilation error:

prog.cpp: In function 'int main()':
prog.cpp:23:35: error: invalid conversion from 'int*' to 'int'
      const int& ref_value = a.get();
                                   ^

It seems that the overloaded get() method with const modifier does get ignored completely and the compiler sees only the non-const definition of it. It is somehow understandable since the a object is not constant. One solution would be to make the a object constant. Though there are other two solutions that makes the code compileable:

  1. Change the signature of the const get() method by different name or other parameters added.

    int* get();
    const int& get_changed() const; <-- this gets called
    
  2. Change the non-const get() method to return a reference instead pointer.

    int& get(); <-- this gets called
    const int& get() const; 
    

though with

int* get();
const int& get() const;

we have a compiler error.

What puzzles me is the reason behind all of these behavior.

Roland
  • 31
  • 3
  • Why is it puzzling? Wouldn't it be more or at elast equally puzzling if the `const` method was called on a non-const object? – juanchopanza Mar 05 '15 at 13:35
  • Yup, this exactly happens in those two cases I mentioned ( const method gets called on non-const object ), so it is still puzzling. – Roland Mar 05 '15 at 13:38
  • If there's only a const method, there is no overload resolution to perform. Only the const method can be called. If there are two overloads, then the non-const gets chosen for a non-const object, and vice versa. I don't find this particularly puzzling. – juanchopanza Mar 05 '15 at 13:42
  • Why compiler error for this? Why not choosing the const method for a non-const object instead of giving the compile error? – Roland Mar 05 '15 at 14:00
  • Searching for some for info in SO, I found the rationale to be somewhat related to C++ being strongly-typed. Letting return type be part of function signature effectively makes implicit/explicit conversion of return value a disaster. Like a comment here, what if return value is discarded? http://stackoverflow.com/questions/9568852/overloading-by-return-type – user3528438 Mar 05 '15 at 14:12
  • @Roland Because the non-const returns a pointer, and you are trying to initialize a reference from that. That is the reason for the compiler error. – juanchopanza Mar 05 '15 at 16:00

2 Answers2

5

When you have both a const and non-const overload of the same function with the same parameters, which one gets called depends only on the constness of the object on which you're invoking the function. So invoking on a non-const a must call the non-const overload.

It's exactly the same situation as this:

void foo(int *p);

void foo(const int *p);


int main()
{
  int i;
  const int ci;
  foo(&i);  // Calls the first overload
  foo(&ci);  // Calls the second overload
}

A const-qualified function can be called on a non-const-qualified object, but that requires a "nonconst to const" conversion. If there's an overload which doesn't require such a conversion (is a better match), it will be preferred.

Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455
3

The reason is that the compiler can't do overload resolution based on a different return type.

Only the function signature is taken into account for overload resolution. And the function signature consists only of the function name, the parameters, and the cv qualifiers - not the return type.

Sander De Dycker
  • 16,053
  • 1
  • 35
  • 40