When should functions be member functions?
Solution 1:
Scott Meyers has advocated that non-member functions often improve encapsulation:
- How Non-Member Functions Improve Encapsulation
Herb Sutter and Jim Hyslop also talk about this (citing Meyer's article) in "Self-Sufficient Headers"
- http://www.ddj.com/cpp/184401705
These ideas have been republished (in more refined form) in the 3rd edition of Meyer's "Effective C++", "Item 23: Prefer non-member non-friend functions to member functions ", and Sutter/Alexandrescu's "C++ Coding Standards", "44 - Prefer writing nonmember nonfriend functions".
I think a lot of developers find this non-intuitive and maybe a little controversial.
Solution 2:
Herb Sutter & Andrei Alexandrescu recommandation about that:
Avoid membership fees: Where possible, prefer making functions nonmember nonfriends.
Non-member nonfriend functions:
- improve encapsulation by minimizing dependencies: The body of the function cannot come to depend on the nonpublic members of the class.
- reduce coupling, by breaking apart monolithic classes to liberate separable functionality
- improve genericity, because it's hard to write templates that don't know whether or not an operation is a member for a given type.
Now, to answer your question (when ?), here is an algorithm to determine whether a function should be a member and/or friend:
If the function is one of the operators =, ->, [], or (), which must be members: => Make it a member Else if: a) the function needs a different type as its left-hand argument (as do stream operators, for example); or b) it needs type conversions on its leftmost argument; or c) it can be implemented using the class's public interface alone: => Make it a nonmember (and friend if needed in cases a) and b) ) If it needs to behave virtually: => Add a virtual member function to provide the virtual behavior, and implement the nonmember in terms of that Else: => Make it a member
References:
- H. Sutter and Andrei Alexandrescu . C++ Coding Standards (Addison-Wesley, 2004)
- S. Meyers . "How Non-Member Functions Improve Encapsulation" (C/C++ Users Journal, 18(2), February 2000)
- B.Stroustrup . The C++ Programming Language (Special 3rdEdition) (Addison-Wesley, 2000). §10.3.2, §11.3.2, §11.3.5, §11.5.2, §21.2.3.1
- H. Sutter . Exceptional C++ (Addison-Wesley, 2000).
- H. Sutter . Exceptional C++ Style (Addison-Wesley, 2004).
Solution 3:
OK
- Your mate is correct, if a method doesn't need to be a member of a class, then - strictly speaking - it should not be a member of a class.
- You are correct, exposing every item on a class, so you can write global functions, is wrong.
Your mate is correct because it's easier to build generic methods if they're not part of a class (e.g. Why is std::find not a member of std::vector? because then it wouldn't work for lists, maps etc).
You are also correct, because exposing too much to do this stuff breaks encapsulation.
When you get out into the real world and start writing apps, and working to business deadlines, you will find that every application is a competing set of requirements. "We need to get A, B, & C in, but by the end of next month. That's, impossible, they can have B & C, or A & C, but not A & B. Or they can have a not-ideal version of A & B and a good version of C".
Writing code is no different, there are plenty of laws and rules that define ideal levels of encapsulation, genericity, cohesion etc, but many of them are contradictory, and you spend so much time trying to satisfy them all that you get nothing done.
I've always said that these principals and "laws" are actually just guide lines, follow them where you can, find your own level where they sit well with you . . . and expect those levels to change every 6 months or so :)
Hope this helps.