This is what I'm trying to do and I can't:
#include <string>
using namespace std;
class A {
public:
bool has() const { return get().length(); }
string& get() { /* huge code her开发者_运维问答e */ return s; }
private:
string s;
};
The error I'm getting is:
passing ‘const A’ as ‘this’ argument of
‘std::string& A::get()’ discards qualifiers
I understand what the problem is, but how can I fix it? I really need has()
to be const
. Thanks.
Add a second overload of get()
:
string const & get() const { return s; }
That will be called on a const
typed object of class A
.
In practice, I prefer adding only const
-typed accessors, and then keeping modifications entirely internal to the class or even avoid them entirely. For example, that means having a method DoUpdateLabel(){/*do something with s*/}
rather than expose the internals. That has the nice side effect that you can avoid duplicating accessors in many cases.
If you absolutely must have modification via accessors and you also don't want an extra const wrapper, you can use const_cast<>
:
bool has() const { return const_cast<A*>(this)->get().length(); }
However, if get()
has side-effects and has()
is declared const
, it's questionable whether this is behavior you really want.
I think your question is a bit vague.
You have:
bool has() const { return get().length(); }
string& get() { /* huge code here */ return s; }
... and need has()
to be const
.
I can think of three ways to get around this, depending on what you're actually trying to do:
The cleanest option would be for has
to only use const
code. If some of your /* huge code here */
code non-const but doesn't actually change the logical value of the class (like computing a cached internal value) consider using mutable
on the data involved.
If the /* huge code here */
part is non-const by nature, consider refactoring it into a different function and calling it separately:
using namespace std;
class A {
public:
bool has() const { return get().length(); }
const string& get() const { return s; }
void computestuff() { /* huge code here */ }
private:
string s;
};
A instance;
// old client code:
// string s = instance.get();
//
// new code:
instance.computestuff(); // non-const call
instance.get(); // const call
instance.has(); // const call
Ultimately, you can also cast the const-ness away (but keep in mind that the need to do so is almost always a sign of bad design/need to refactor):
class A {
public:
bool has() const { return const_cast<A*>(this)->get().length(); }
string& get() { /* huge code here */ return s; }
private:
string s;
};
It's pretty usual to have const
and non-const
versions of the same functions.
So, one of them would be called if your object is called as a const
object, and the second - if the same happens with a non-const
.
I have to mention, that this technique usually is used with operators but is also suitable for you current case.
Also, in your current case the best approach could mean having ONLY const
method like
const string& get() const { return s }
and refactoring all your other code so it works with a string returned via constant reference.
std::string get() const { return s; }
because passing strings by value is usually cheap (I don't remember if this is a guarantee), and I don't think you want the string you're looking at to change under your feet when A modifies it.
Try this:
const string& get() const { return s; }
The first const applies to the return type of the method get(). The return type is a reference to a string. Altogether it's a const reference to a string, which enforces that this returb value is not to be changed.
The second const applies to the method, effectively making it a const method.
精彩评论