Calling a const function from a non-const object

2020-02-05 11:57发布

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.

11条回答
啃猪蹄的小仙女
2楼-- · 2020-02-05 12:51

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();
查看更多
女痞
3楼-- · 2020-02-05 12:51

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.

查看更多
▲ chillily
4楼-- · 2020-02-05 12:51

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

查看更多
地球回转人心会变
5楼-- · 2020-02-05 12:53

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();
查看更多
甜甜的少女心
6楼-- · 2020-02-05 13:00

define a template

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

and call

addConst( getProcess() ).doSomeWork();
查看更多
登录 后发表回答