Pinnacle Encapsulation - A Question About Advice With Effective C ++

Paragraph 23 of effective C ++ states: Prefer functions that are not non-member members to member functions.

The whole purpose of this subject was to encourage encapsulation as well as package flexibility and functional extensibility, but my question is: how far do you go when it comes to taking this advice?

For example, you can have your class, your personal data, and then take a minimalist approach, reducing public functions only for access and / or mutators for your personal data. Then every other function can be a function that is not a member.

However, are you ready to increase encapsulation with a possible sacrifice of code clarity with accessories and mutators everywhere? Where is the line located?

+6
c ++ encapsulation
source share
5 answers

Firstly, not everyone agrees with this advice. I don't think I saw anyone other than Meyers ( edit: and Herb Sutter ) give this advice, and I saw it only in the context of C ++. For example, creating “non-member functions different from one another” in Java or C # is actually not possible since Java and C # do not have free functions, and Ruby developers (for example) prefer “humane interfaces” that intentionally create member functions who do the same as non-members to simply make life easier for subscribers of these features.

And even if you accept Meyers advice, you should prefer functions other than non-member members to member functions (and I think this is good advice, this certainly helped me apply encapsulation to better think about encapsulation of a class implementation, even from its member functions), to consider only one design axis.

The key concept of object-oriented design is that objects do something . An object is not just a bag of setters and getters, to which another code adds. Instead, it must have attached behavior, that is, it must have methods that do something, and it must encapsulate the details of how this happens. If you follow this approach to OO, then bring Meyers' recommendations to the end, since you did encapsulation rather than helping it: you end up exposing all the internal variables of the class implementation through getters and setters, rather than hiding them so that only the class methods (the code responsible for executing the material on behalf of the class, which is the only reason you are starting to start) can get to it.

So, to answer your question about how far to take Meyers advice: it is not necessary to unnecessarily turn functions into member functions if they can be reasonably implemented as functions that are not non-member members using the public interface class, but Do not damage the open interface of the class and break its encapsulation, exposing the implementation simply so as not to make something a member. And make sure that you balance encapsulation against other problems and other approaches (including, if your team decides to take this route, the pros and cons of a full-scale humane interface).

+9
source share

Take a step back and consider the purpose of the class: what is this one work? What class invariants should ensure optimal performance? What role do subclasses and redefinition of the game play for class?

It is definitely impractical to drop everything in terms of accessories and mutators: it almost explores the combination of state and behavior that underlies OOP, or the behavior of a mask that, without a reasonable frame of the problem, is associated with obtaining or setting attributes under the veil of such “mock” mutators and accessories.

Classes using only accessories and mutators - this is one special case - perhaps one step from the traditional C-kind struct , preserving some invariants, but "hardly"; -).

Most classes in a good OOP design will have behavior - and, as I like it, general programming, one of the reasons for using C ++ is its strong combination of several paradigms, among which OOP should not be deleted! -)

+3
source share

In fact, providing only accessories and mutators in your private class variables would not really be minimalist (or perhaps minimalistic in one sense, but not in the “most important” sense), since now you are introducing a more general interface to the World. The idea behind encapsulation is that your class interface should be as limited as possible , allowing the client code to complete the task.

Following this approach, it is easier to change the underlying implementation in the future, which is primarily an encapsulation point.

+2
source share

In general, the idea behind accessories is that the variable must be somehow protected. if the variable has confidential information that needs to be updated with only one object, you can include this check in your mutator. The simple fact is that most accessories and mutators are just a formality (so much so that C # now has automatic properties) and are not needed. On the bottom line, use your opinion. if he needs limited access, add a mutator. If it does not matter who gets / sets the variable, then no accessor and mutator are needed.

0
source share

Work on how to pack things into the right units is a subjective art.

One of the problems that I encounter in creating something that is not a member is not a friend, is that if the change in the internal structure requires the addition of new public interfaces to support existing non-members, or that the non-member will now be recognized friend, you show a closer connection than was previously developed. It can now become costly to make any changes.

While at the logical level it can be said that a non-member function can be packaged with the class and make up the class interface, the developer will need to change the code if the location of the method changes, and therefore the implementation of the interface is not executed, errr is transparent in it.

One of these nice things about the Eiffel, the parameterless method is available as well as the variable, so the change between these elements is transparent.

0
source share

All Articles