Calling a const function from a non-const object
Solution 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.
Solution 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();
Solution 3
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();
Solution 4
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
.
Solution 5
define a template
template< class T >
const T & addConst ( T & t )
{
return t;
}
and call
addConst( getProcess() ).doSomeWork();
Related videos on Youtube
Bhupendra Jadeja
Updated on July 09, 2022Comments
-
Bhupendra Jadeja almost 2 years
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.
-
Bhupendra Jadeja over 15 yearsI tried the above before posting. To my surprise the non-const function was called anyway. I will confirm this again on Monday.I am working in MS VS6 - could be a compiler issue. Thanks for a quick answer.
-
Bhupendra Jadeja over 15 yearsUnfortunately, no. doOtherWork() has to be non constant.
-
MSalters over 15 yearsYour solution fails to work anyway; a smart_cow_ptr<T> cannot know if T has mutable members.
-
Judge Maygarden over 15 yearsAre there side effects from the getProcess function? Otherwise, why does it matter which one is called?
-
Bhupendra Jadeja over 15 yearsthere is only one definition of each - void doOtherWork() - virtual bool doSomeWork() const
-
Mr Fooz over 15 yearsThe point of the example is that it doesn't work in a useful way. If you const_cast<smart_cow_ptr<T>&>(ptr)->some_const_member(), it'll work fine, but the requirement to do the const_cast IMHO makes it too painful to use a cow pointer.
-
mfazekas over 15 years"Copy on write" is a an example when the const/non const could return different objects, so it's not always bad design.
-
Bhupendra Jadeja over 15 yearsYou can actually safely do both - cast away and cast the constness in.
-
Admin over 15 yearsThen may be the override is misadvised here. What is the diff between getProcess() const and plain? Is it caching? If so, the official solution is "mutable".
-
Ankit Roy over 15 yearsYes, but mfazekas' point is that you only need const_cast<> to remove constness, and it's in your own interests to use the "smallest weapon that will do the job" (i.e. static_cast<>), since that way all occurrences of const_cast are code smells which can be easily grepped for.
-
CB Bailey over 15 yearsI'd still say that overloading on const and returning anything other than a proxy class is a poor way to implement copy on write. If something that just happens to have non-const reference has to perform a const_cast to avoid a pessimistic copy, this will often be missed and performance will suffer.
-
Ankit Roy over 15 yearsWhat are the pedantic reasons you speak of? I would have thought that a big ugly cast makes your intentions clearer than an assignment to a const Bar *, but that's just my opinion.
-
Ankit Roy over 15 yearsActually, as mfazekas pointed out, it suffices to use static_cast<> instead of const_cast<> in this case, as you are adding rather than removing constness, which is always a safe operation.
-
MSN over 15 yearsThe only way this tends to cause unexpected behavior is when the return value of getProcess() changes its cv-qualifier (i.e., becomes volatile). The const_cast<> will succeed, but it will be doing something much different compared to the original intent. An assignment would catch that. MSN