Calling a const function from a non-const object

28,522

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

Solution 5

define a template

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

and call

addConst( getProcess() ).doSomeWork();
Share:
28,522

Related videos on Youtube

Bhupendra Jadeja
Author by

Bhupendra Jadeja

Updated on July 09, 2022

Comments

  • Bhupendra Jadeja
    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
    Bhupendra Jadeja over 15 years
    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.
  • Bhupendra Jadeja
    Bhupendra Jadeja over 15 years
    Unfortunately, no. doOtherWork() has to be non constant.
  • MSalters
    MSalters over 15 years
    Your solution fails to work anyway; a smart_cow_ptr<T> cannot know if T has mutable members.
  • Judge Maygarden
    Judge Maygarden over 15 years
    Are there side effects from the getProcess function? Otherwise, why does it matter which one is called?
  • Bhupendra Jadeja
    Bhupendra Jadeja over 15 years
    there is only one definition of each - void doOtherWork() - virtual bool doSomeWork() const
  • Mr Fooz
    Mr Fooz over 15 years
    The 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
    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
    Bhupendra Jadeja over 15 years
    You can actually safely do both - cast away and cast the constness in.
  • Admin
    Admin over 15 years
    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".
  • Ankit Roy
    Ankit Roy over 15 years
    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.
  • CB Bailey
    CB Bailey over 15 years
    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.
  • Ankit Roy
    Ankit Roy over 15 years
    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.
  • Ankit Roy
    Ankit Roy over 15 years
    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.
  • MSN
    MSN over 15 years
    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