Large scale usage of Meyer's advice to prefer Non-member,non-friend functions?

后端 未结 8 1082
無奈伤痛
無奈伤痛 2021-02-05 00:15

For some time I\'ve been designing my class interfaces to be minimal, preferring namespace-wrapped non-member functions over member functions. Essentially following Scott Meyer

相关标签:
8条回答
  • 2021-02-05 01:12

    I'd argue that the benefit of non-member functions increases as the size of the project increases. The standard library containers, iterators, and algorithms library are proof of this.

    If you can decouple algorithms from data structures (or, to phrase it another way, if you can decouple what you do with objects from how their internal state is manipulated), you can decrease coupling between your classes and take greater advantage of generic code.

    Scott Meyers isn't the only author who has argued in favor of this principle; Herb Sutter has too, especially in Monoliths Unstrung, which ends with the guideline:

    Where possible, prefer writing functions as nonmember nonfriends.

    I think one of the best examples of an unneccessary member function from that article is std::basic_string::find; there is no reason for it to exist, really, as std::find provides exactly the same functionality.

    0 讨论(0)
  • 2021-02-05 01:20

    One practical advantage of writing functions as nonmember nonfriends is that doing so can significantly reduce the time it takes to thoroughly test and verify the code.

    Consider, for example, the sequence container member functions insert and push_back. There are at least two approaches to implementing push_back:

    1. It can simply call insert (it's behavior is defined in terms of insert anyway)
    2. It can do all the work that insert would do (possibly calling private helper functions) without actually calling insert

    Obviously, when implementing a sequence container, you probably want to use the first approach. push_back is just a special form of insert and (to the best of my knowledge) you can't really get any performance benefit by implementing push_back some other way (at least not for list, deque, or vector).

    However, to thoroughly test such a container, you have to test push_back separately: since push_back is a member function, it can modify any and all of the internal state of the container. From a testing standpoint, you should (must?) assume that push_back is implemented using the second approach because it is possible that it could be implemented using the second approach. There is no guarantee that it is implemented in terms of insert.

    If push_back is implemented as a nonmember nonfriend, it can't touch any of the internal state of the container; it must use the first approach. When you write tests for it, you know that it can't break the internal state of the container (assuming the actual container member functions are implemented correctly). You can use that knowledge to significantly reduce the number of tests that you need to write to fully exercise the code.

    0 讨论(0)
提交回复
热议问题