Search code examples
c++c++11referenceconstantsconst-cast

Why can't a const method return a non-const reference?


Why won't the method getRanks() below compile, and how can I fix it gracefully?

All I want do is define a member accessor method that returns a reference to a member. The reference is not const since I might well modify what it refers to later. But since the member method does not modify the object, I declare it const. The compiler (clang, std=c++11) then insists that there is a "binding of reference" that "drops qualifiers". But I'm NOT dropping qualifiers, am I? And if I am, why:

struct teststruct{
  vector<int> ranks;
  vector<int>& getRanks()const{
    return ranks;
  }
};

Now, the code compiles if I change the return statement to cast away the const:

return const_cast<vector<int>&>(ranks);

But "ranks" should not be const in the first place, I don't see why I need to const_cast the const away. I don't even know if it's safe to do this.

Anyway, is there a cleaner to write this method? Can someone explain why such a simple common-sense method fails? I do want to declare the getRanks() method "const" so that I can call it from other const methods.


Solution

  • The idea behind the const member function is you should be able to call them on const objects. const functions can't modify the object.

    Say you have a class

    class A
    {
       int data;
       void foo() const
       {
       }
    };
    

    and on object and a function call:

    A const a;
    a.foo();
    

    Inside A::foo, this->data is treated as if its type is int const, not int. Hence, you are not able to modify this->data in A:foo().

    Coming to your example, the type of this->ranks in getRanks() is to be considered as const vector<int> and not vector<int>. Since, auto conversion of const vector<int> to vector<int>& is not allowed, the compiler complains when you define the function as:

    vector<int>& getRanks()const{
        return ranks;
      }
    

    It won't complain if you define the function as:

    const vector<int>& getRanks()const{
        return ranks;
      }
    

    since const vector<int> can be auto converted to const vector<int>&.