In the (otherwise) excellent book C++ Coding Standards, Item 44, titled ‘Prefer writing nonmember nonfriend functions’, Sutter and Alexandrescu recommend that only functions that really need access to the members of a class be themselves members of that class. All other operations which can be written by using only member functions should not be part of the class. They should be nonmembers and nonfriends. The arguments are that:
- It promotes encapsulation, because there is less code that needs access to the internals of a class.
- It makes writing function templates easier, because you don’t have to guess each time whether some function is a member or not.
- It keeps the class small, which in turn makes it easier to test and maintain.
Although I see the value in these argument, I see a huge drawback: my IDE can’t help me find these functions! Whenever I have an object of some kind, and I want to see what operations are available on it, I can’t just type ‘pMysteriousObject->‘ and get a list of member functions anymore.
Keeping a clean design is in the end about making your programming life easier. But this would actually make mine much harder.
So I’m wondering if it’s really worth the trouble. How do you deal with that?
I’m going to have to disagree with Sutter and Alexandrescu on this one. I think if the behavior of function
foo()falls within the realm of classBar‘s responsibilities, thenfoo()should be part ofbar().The fact that
foo()doesn’t need direct access toBar‘s member data doesn’t mean it isn’t conceptually part ofBar. It can also mean that the code is well factored. It’s not uncommon to have member functions which perform all their behavior via other member functions, and I don’t see why it should be.I fully agree that peripherally-related functions should not be part of the class, but if something is core to the class responsibilities, there’s no reason it shouldn’t be a member, regardless of whether it is directly mucking around with the member data.
As for these specific points:
Indeed, the fewer functions that directly access the internals, the better. That means that having member functions do as much as possible via other member functions is a good thing. Splitting well-factored functions out of the class just leaves you with a half-class, that requires a bunch of external functions to be useful. Pulling well-factored functions away from their classes also seems to discourage the writing of well-factored functions.
I don’t understand this at all. If you pull a bunch of functions out of classes, you’ve thrust more responsibility onto function templates. They are forced to assume that even less functionality is provided by their class template arguments, unless we are going to assume that most functions pulled from their classes is going to be converted into a template (ugh).
Um, sure. It also creates a lot of additional, external functions to test and maintain. I fail to see the value in this.