Question

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.

Was it helpful?

Solution

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.

OTHER TIPS

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();

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

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();

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.

define a template

template< class T >
const T & addConst ( T & t ) 
{
    return t;
}

and call

addConst( getProcess() ).doSomeWork();

Well, can you declare

void doOtherWork const ()

?

That would do it.

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();

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.

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.

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

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top