Is it a good practice to make a method which modif

2020-07-06 06:28发布

问题:

I would like to ask a question about methods' const-correctness. Let me illustrate the situation.

class MyClass
{
public:
    ...
    void DiscussedMethod() { otherClass->NonConstMethod(); }

private:
    OtherClass *otherClass;
};

I have a class MyClass which keeps a pointer to OtherClass. In DiscussedMethod it calls OtherClass::NonConstMethod which modifies some visible data.

I would like to know, whether it would be a good practice to make the DiscussedMethod const (since it doesn't modify any member data)? Would it be a bad practice? Or is both fine?

What if the OtherClass kept a pointer to the MyClass and in NonConstMethod modified some of the MyClass' data (meaning that the MyClass member data would change during the DiscussedMethod call). Would it be a bad practice to make the DiscussedMethod const then?

As far as I've been able to find out, the const on a method is mostly a code documenting thing, so I would probably lean toward to not making the DiscussedMethod const, but I would like to hear your opinions.

EDIT: Some replies take the into account whether the object pointed to by otherClass is owned by the MyClass object. This is not the case in the scenario I'm working with. Lets say that both objects exist independently side by side (with the ability to modify each other). I think this analogy describes my situation quite well.

For example consider something like doubly-linked list, where each element is a class that keeps pointer to its neighbours and member variable color. And it has method MakeNeighboursRed which changes the color of its neighbours but doesn't affect the calling object's state itself. Should I consider making this method const?

And what if there was some possibility that MakeNeighboursRed would call neighbour's MakeNeighboursRed. So in the end the state of the object for which MakeNeighboursRed has been called originally would change as well.

And I would like to thank you all for your opinions :-)

回答1:

If MyClass owns the OtherClass instance i wouldn't make DiscussedMethod constant.

The same goes for classes, managing resources. I.e. the standard containers do not return non const references or pointers to the managed memory using const functions, although it would be "possible" (since the actual pointer holding the resource is not modified).

Consider

class MyClass
{
public:
    bool a() const { return otherClass->SomeMethod(); }
    void b() const { otherClass->NonConstMethod(); }
private:
    OtherClass *otherClass;
};

void foo (MyClass const &x)
{
    cout << boolalpha << x.a() << endl;
    x.b(); // possible if b is a const function
    cout << boolalpha << x.a() << endl;
}

The foo could print two different values although an implementor of foo would probably expect that two function calls on a const object will have the same behaviour.

For clarification:

The following is invalid according to the standard since the const version of operator[] returns std::vector<T>::const_reference which is a constant reference to the value type.

std::vector<int> const a = { /* ... */ };
a[0] = 23; // impossible, the content is part of the state of a

It would be possible if there was only one signature of this function, namely referece operator[] (size_t i) const;, since the operation does not alter the internal pointers of the vector but the memory they point to.

But the memory, managed by the vector is considered to be part of the vectors state and thus modification is impossible through the const vector interface.

If the vector contains pointers, those pointer will still be unmodifiable through the public const vector interface, although the pointers stored in the vector may well be non const and it may well be possible to alter the memory they point to.

std::vector<int*> const b = { /* ... */ };
int x(2);
b[0] = &x; // impossible, b is const
*b[0] = x; // possible since value_type is int* not int const *


回答2:

In OOP object should be fully described by its state, available through its interface. Thus, const methods should not alter object's state, if these changes might be observed through the interface.

A good example is a mutable mutex inside your class to guard some shared resources. It might be modified from const method, since it does not introduce any changes observable via class interface.



回答3:

General rule of thumb is, that if you can make a member function const, you probably should. The reason for that is that it allows you to catch unintended behaviour and bug easier.

Another argument in favor would be that if you have this function as const you are allowed to call it on const object, so it isn't really a documentation thing.



回答4:

Overall it depends what the other class is. It's not black and white...

If otherClass is a log object (for example) and you want to log the operation of the current object then it's perfectly fine calling it from a const function.

If the otherClass is a container that for design (or implementation) purposes is implemented as a separate object than effectively a const function modifies the object making this a very bad idea.

I hope this helps.



回答5:

It's totaly incorrect to make DiscussedMethod const as it changes it's *this state. The only loophole to this is making non-logically-part-of-object's-state member data mutable so they can be changed in const functions. This would be things like a member that hold a count for "number of times function x() has been called". Any thing else is part of the object's state, and if a function changes it (at any level), that function isn't const.



回答6:

I would like to know, whether it would be a good practice to make the DiscussedMethod const (since it doesn't modify any member data)?

otherClass is member data, and it (or rather, the object it points to) gets modified.

Consider the semantics should the pointer to otherClass be refactored to a fully-owned object... whether something is held as a pointer, reference, or object doesn't change the semantical ownership, IMO.