可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I need to call a const function from a non-const object. See example
struct IProcess {
virtual bool doSomeWork() const = 0L;
};
class Foo : public IProcess {
virtual bool doSomeWork() const {
...
}
};
class Bar
{
public:
const IProcess& getProcess() const {return ...;}
IProcess& getProcess() {return ...;}
void doOtherWork {
getProcess().doSomeWork();
}
};
Calling
getProcess().doSomeWork();
will always results in a call to
IProcess& getProcess()
Is there another way to call
const IProcess& getProcess() const
from a non constant member function?
I have so far used
const_cast<const Bar*>(this)->getProcess().doSomeWork();
which does the trick but seems overly complicated.
Edit: I should mention that code is being refactored and eventually only one function will remain.
const IProcess& getProcess() const
However, currently there is a side effect and the const call may return a different instance of IProcess some of the time.
Please keep on topic.
回答1:
Avoid the cast: assign this to a const Bar *
or whatever and use that to call getProcess()
.
There are some pedantic reasons to do that, but it also makes it more obvious what you are doing without forcing the compiler to do something potentially unsafe. Granted, you may never hit those cases, but you might as well write something that doesn't use a cast in this case.
回答2:
const_cast
is for casting away constness!
You're casting from non-const to const which is safe, so use static_cast
:
static_cast<const Bar*>(this)->getProcess().doSomeWork();
I mean techincally speaking you can cast in constness with const_cast
, but it's not a pragmatic use of the operator. The purpose of new style casts (versus the old c-style cast), is to communicate the intent of the cast. const_cast
is a code smell, and it's use should be reviewed at least. static_cast
on the other hand is safe. But it's a matter of C++ style.
Or you can create a new (private) const method, and call that from doOtherWork
:
void doSomeWorkOnProcess() const { getProcess().doSomeWork(); }
Using a const temporary is also an option (answer by "MSN"):
const Bar* _this = this;
_this->getProcess().doSomeWork();
回答3:
If getProcess()
and getProcess() const
are not returning a reference to the same object (but differently qualified) then it would indicate a poor design of class Bar
. Overloading on the const
ness of the function is not a good way to distinguish functions with different behaviours.
If they are returning a reference to the same object then:
const_cast<const Bar*>(this)->getProcess().doSomeWork();
and
getProcess().doSomeWork();
call exactly the same doSomeWork()
function so there is no need to use the const_cast
.
回答4:
If the cast is too ugly for you, you could instead add a method to Bar
that simply returns a const reference to *this
:
Bar const& as_const() const {
return *this; // Compiler adds "const" without needing static_cast<>
}
You can then call any const
method in Bar
just by prepending as_const().
, e.g.:
as_const().getProcess().doSomeWork();
回答5:
You don't have to do any casting trickery if the function is not overloaded. Calling a const method of a non-const object is fine. It's calling a non-const method from a const object that is forbidden. If the methods are overridden with a const and non-const function, then casting the object to const will do the trick:
const_cast<const IProcess&> (getProcess()).doSomeWork();
EDIT: I didn't read the whole question. Yes, you need to const_cast the this pointer or make the doOtherWork function const to call const IProcess& getProcess() const.
The point remains that you don't need a const object to call doSomeWork. Since that is the goal, do you need the const method called?
Another option would be to rename the over-ridden functions. This would be a really good idea if the two function actually have different behavior/side-effects. Otherwise, the effect of the function call would not be obvious.
回答6:
define a template
template< class T >
const T & addConst ( T & t )
{
return t;
}
and call
addConst( getProcess() ).doSomeWork();
回答7:
Well, can you declare
void doOtherWork const ()
?
That would do it.
回答8:
I think the const_cast method is your best option. This is just a limitation of the const framework in C++. I think the only way you could avoid the casting is to define a method which returns const IProcess instance regardless. For instance.
const IProcess* getProcessConst() const { return ... }
...
getProcessConst().doSomeWork();
回答9:
I assume you want DoOtherWork to call one of your two getprocess calls depending on on whether it's called from a const object or not.
The best I can suggest is this:
class Bar
{
public:
const IProcess& getProcess() const {return ...;}
IProcess& getProcess() {return ...;}
void doOtherWork { // should use getProcess()
getProcess().doSomeWork();
}
void doOtherWork const {
getProcess().doSomeWork(); // should use getProcess() const
}
};
Even if that works, this looks like a bad smell to me. I'd be very wary of the class behaviour changing radically according to the constness of an object.
回答10:
Posted by monjardin
Another option would be to rename the over-ridden functions. This would be a really good idea if the two function actually have different behavior/side-effects. Otherwise, the effect of the function call would not be obvious.
IProcess& is accessed in other code mostly through a property
__declspec(property(get=getProcess)) IProcess& Process;
so renaming was not an option. Majority of the time constness of the calling function matches getProcess() so there was no issue.
回答11:
You're basically stuck with renaming the other method or const_cast.
BTW, this is one of the reasons that copy-on-write smart pointers don't actually work well in C++. A copy-on-write smart pointer is one that can be shared infinitely. When a user accesses the data in a non-const context, a copy of the data is made (if the user doesn't hold the unique reference). This kind of pointer can be very convenient to use when sharing large data structures that only some clients need to modify. The most "logical" implementation is to have a const and a non-const operator->. The const version just returns the underlying reference. The non-const version does the unique reference check and copying. It fails to be useful because a non-const smart pointer will use the non-const operator-> by default, even if you wanted to use the const version. The const_cast requirement makes it very user-unfriendly.
I'm welcoming anyone who proves me wrong and shows a user-friendly copy-on-write pointer in C++...