简体   繁体   中英

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.

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

ranks is const because the enclosing object ( *this ) is const , so you have to return a reference to a std::vector<int> const .

If you want to allow the client to modify the vector (and thereby affecting the member), then the getter should not be const . Note that the getter is silly anyway, since ranks is already a public data member.

You are returning a reference to ranks , which is a member of teststruct . That means that anybody that gets this reference could modify the internals of the teststruct object. So the const is a lie.

Don't cast away the const . Instead, decide between whether you want the function to be const and return a copy of ranks or const reference, or to be non- const and return a mutable reference. You can always have both if necessary.

It drops qualifiers because you return a reference to ranks . Any code after can modify ranks. Ex:

auto v = teststruct.getRanks();
v[1] = 5; //assuming v.size() > 1

You can fix this by returning a copy:

vector<int> getRanks() const

Or a const reference:

const vector<int>& getRanks() const

If you want ranks changable even in a const object, you could do this:

mutable vector<int> ranks;

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