简体   繁体   中英

C++ const problems when member value is changed from pointer to non-pointer

I have two classes TestClass and OtherClass , where TestClass has a member variable of type OtherClass named m_otherClass . Note that this is not declared to be const.

In the minimal example provided below; when m_otherClass is a pointer, then everything compiles and runs fine. If I change this to be a non-pointer, then I get compiler errors (the changes are commented out in the minimal example):

"Non-const function 'setOtherMember' is called on const object"

error: passing 'const OtherClass' as 'this' argument discards qualifiers [-fpermissive] m_otherClass.setOtherMember();

#include <iostream>
#include <memory>

class OtherClass {
public:
    void setOtherMember() {
        m_otherMember = 2;
        std::cout << "Other member is now 2" << std::endl;
    }

private:
    int m_otherMember = 0;
};


class TestClass {
public:
    TestClass(): m_otherClass(std::make_unique<OtherClass>())
//  TestClass()
    {}

    void myMethod() const {
        m_otherClass->setOtherMember();
//      m_otherClass.setOtherMember();
    }
private:
        std::unique_ptr<OtherClass> m_otherClass;
//      OtherClass m_otherClass; // If changing to this I get the error!!
};


int main() {
    TestClass testClass;
    testClass.myMethod();
    return 0;
}

Is this because myMethod() is const (and then promising not to change any member variables), whereas setOtherMember() is non-const and is changing OtherClass 's member variable, and then indirectly also the m_otherClass object?

But why does this not fail then when m_otherClass is a pointer? And why does the compiler error says that passing 'const OtherClass' as 'this'argument fails, when m_otherClass has not been declared to be const?

Const qualified member functions in most cases aren't allowed to change an object's members state. This means, that every member which is not mutable can not be modified in this function body. When dealing with pointers, you just say, that you won't modify a pointer value, not a pointee itself. It is because constness of a pointer is not propagated on its pointee .

In the upcoming standards it will be possible to change this behaviour by using propagate_const .

A simpler example to demonstrate the difference.

struct Foo { int m; };

const Foo f = {10}; 
f.m = 20; // Not allowed since modifying f.m modifies f.

struct Bar { int* p; };
int i = 10;
int j = 20;

const Bar b = {&i};

b.p = &j;    // Not allowed since modifying b.p modifies b.

*(b.p) = j;  // Allowed since it does not change b or b.p. It changes the value
             // of what b.p points to.

But why does this not fail then when m_otherClass is a pointer?

Because it is const correct to modify an object pointed by a const pointer, as long as it is a pointer to non-const such as in your case.

And why does the compiler error says that passing 'const OtherClass' as 'this'argument fails, when m_otherClass has not been declared to be const?

myMethod is declared const. Therefore this is a pointer to const. Therefore the lvalue this->m_otherClass is also const regardless of whether the object named by the lvalue is const or not.

When you put const on a method, all your data members are treated as being const. And that is why you get the error when you have OtherClass as a value, since it turns into a value of const OtherClass .

Now when you use a pointer of OtherClass you get const std::unique_ptr<OtherClass> and the const applies only to the pointer but not to the value it points to.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM