views:

2256

answers:

10

Hi,

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  A: 

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.

Judge Maygarden
I 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.
Chris
Are there side effects from the getProcess function? Otherwise, why does it matter which one is called?
Judge Maygarden
Actually, 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.
j_random_hacker
A: 

Well, can you declare

void doOtherWork const ()

?

That would do it.

Arkadiy
Unfortunately, no. doOtherWork() has to be non constant.
Chris
Then 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".
Arkadiy
A: 

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

Mr Fooz
Your solution fails to work anyway; a smart_cow_ptr<T> cannot know if T has mutable members.
MSalters
Mr Fooz
A: 

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();
JaredPar
+4  A: 

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.

Charles Bailey
"Copy on write" is a an example when the const/non const could return different objects, so it's not always bad design.
mfazekas
I'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.
Charles Bailey
A: 

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.

Roddy
there is only one definition of each - void doOtherWork() - virtual bool doSomeWork() const
Chris
A: 

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.

Chris
+3  A: 

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.

MSN

MSN
What 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.
j_random_hacker
The 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
MSN
+2  A: 

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();
mfazekas
You can actually safely do both - cast away and cast the constness in.
Chris
Yes, 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.
j_random_hacker
A: 

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