When should a member function have a const qualifier and when shouldn't it?

后端 未结 6 1428
轻奢々
轻奢々 2021-02-06 09:04

About six years ago, a software engineer named Harri Porten wrote this article, asking the question, \"When should a member function have a const qualifier and when shouldn\'t i

6条回答
  •  我寻月下人不归
    2021-02-06 09:36

    The article seems to cover a lot of basic ground, but the author still has a question about const and non-const overloads of functions returning pointers. Last line of the article is:

    Many will probably answer "It depends." but I'd like to ask "It depends on what?"

    To be absolutely precise, it depends whether the state of the A object pointee is logically part of the state of this object.

    For an example where it is, vector::operator[] returns a reference to an int. The int referand is "part of" the vector, although it isn't actually a data member. So the const-overload idiom applies: change an element and you've changed the vector.

    For an example where it isn't, consider shared_ptr. This has the member function T * operator->() const;, because it makes logical sense to have a const smart pointer to a non-const object. The referand is not part of the smart pointer: modifying it does not change the smart pointer. So the question of whether you can "reseat" a smart pointer to refer to a different object is independent of whether or not the referand is const.

    I don't think I can provide any complete guidelines to let you decide whether the pointee is logically part of the object or not. However, if modifying the pointee changes the return values or other behaviour of any member functions of this, and especially if the pointee participates in operator==, then chances are it is logically part of this object.

    I would err on the side of assuming it is part (and provide overloads). Then if a situation arose where the compiler complains that I'm trying to modify the A object returned from a const object, I'd consider whether I really should be doing that or not, and if so change the design so that only the pointer-to-A is conceptually part of the object's state, not the A itself. This of course requires ensuring that modifying the A doesn't do anything that breaks the expected behaviour of this const object.

    If you're publishing the interface you may have to figure this out in advance, but in practice going back from the const overloads to the const-function-returning-non-const-pointer is unlikely to break client code. Anyway, by the time you publish an interface you hopefully have used it a bit, and probably got a feel for what the state of your object really includes.

    Btw, I also try to err on the side of not providing pointer/reference accessors, especially modifiable ones. That's really a separate issue (Law of Demeter and all that), but the more times you can replace:

    A *getA();
    const A *getA() const;
    

    with:

    A getA() const; // or const A &getA() const; to avoid a copy
    void setA(const A &a);
    

    The less times you have to worry about the issue. Of course the latter has its own limitations.

提交回复
热议问题