Can you change state in a const function in C++? Why? How?

In this post, we discuss why you might want to change the state in a const function in C++, and how you can change the state using const_cast. We also discuss whether it is a good practice to use const_cast in C++ codebases.

Can you change state in a const function in C++? Why? How?

Why should you have const functions in your codebase?

Many object-oriented codebases often make a member function const, meaning that the function will never mutate or change the value of a class data member.

They act as a safety measure, ensuring that multiple developers working on the same code don't unintentionally alter class members, preventing unexpected changes in data accessed by other parts of the codebase.

Okay, then why would you want to change the state in a const function?

If you work on a codebase in a small team of developers, you might never run into this problem. However, if you're working on legacy code, you might.

Object-oriented codebases heavily use inheritance. Therefore, if you want to override a const function, the overriding function must also be const. So, if we have a long list of classes inheriting from one another, we will have long chains of overriding const functions.

class A {
public:
    virtual void display() const {
        std::cout << "A display" << std::endl;
    }
};

class B : public A {
public:
    void display() const override {
        std::cout << "B display" << std::endl;
    }
};

class C : public B {
public:
    void display() const override {
        std::cout << "C display" << std::endl;
    }
};

class D : public C {
public:
    void display() const override {
        std::cout << "D display" << std::endl;
    }
};

It might happen that when you write D::display(), you might WANT to change a data member of the class. Why? It might be possible that you are writing code on top of legacy code written by developers several years earlier, with a different philosophy in mind.

Alright, so what do we do in this case? Let's consider the following solutions.

Can we make D::display() a non-const function? No, because a non-const member function cannot override a const member function, due to the difference in function signature.

Okay, what if we make all the displays() a non-const function?

It is quite possible that display() shouldn't have been declared as const in the first place. Now you face a decision: either undertake the responsibility significant refactor to convert all instances of display() to non-const, or opt for the easier route — carry forward the legacy and make it a const function and search for a “hacky” work-around.

If you choose to do the refactor, you also have the risk of anyone mutating the state in A::display(), B::display(), C::display() or D::display(), since all of them are non-const.

Can you call a non-const function from a const function in C++?

What if we call a non-const method from display()?

It will give you a compiler error. In C++, you cannot directly call a non-const member function from a const member function because a const member function promises not to modify the object's state, and calling a non-const member function could violate that promise.

However, there is a “hacky” way to mutate the state of a class using const_cast.

const_cast essentially casts away the "const-ness" of a variable.

#include <iostream>

class MyClass {
public:
    MyClass(int val) : value(val) {}

    // Const member function
    void constFunction() const {
        std::cout << "Inside constFunction" << std::endl;
        // Calling a non-const function from a const function
        const_cast<MyClass*>(this)->nonConstFunction();
    }

    // Non-const member function
    void nonConstFunction() {
        std::cout << "Inside nonConstFunction" << std::endl;
        // Modify the value
        value = 20;
    }

    void showValue() const {
        std::cout << "Value: " << value << std::endl;
    }

private:
    int value;
};

int main() {
    MyClass obj(10);

    std::cout << "Initial value: ";
    obj.showValue(); // 10

    // Call const function which internally calls non-const function
    obj.constFunction();

    std::cout << "Value after constFunction call: ";
    obj.showValue(); // 20

    return 0;
}

Should you use const_cast in C++ codebases?

No. Using const_cast is not a good practice if you’re working on anything serious. const_cast can only modify data members that are not declared as const. Using const_cast to mutate a const data member leads to undefined behavior (which is never what anyone wants).

So as an example, if the value in the above example were declared as const, then constFunction() can have undefined behavior.

Using mutable

You can make a class member mutable, which allows a const member function to mutate it.


class Foo  
{  
private:  
    mutable bool done_;  
public:  
    void doSomething() const { ...; done_ = true; }  
};

Personal Experience

From my experience, I usually review why I might need to change the state in a const function, and then find better places where I can do the same. If you're running into this issue, it is usually a design flaw. Alternatively, consider why the method was made const in the first place and whether it really needs to be const.

Illustration prompt: Cartoon of a const function calling a non-const function.