Reading Notes Objective c ++ Item 23 would rather use non-member, non-friend functions than member functions. Objective tiveitem
1. is non-member membership good or is the member function good?
Imagine a class that represents a web browser. Such a class can clear the download cache, clear the URL access history, and remove all cookies from the system:
1 class WebBrowser { 2 3 public: 4 5 ... 6 7 void clearCache(); 8 9 void clearHistory();10 11 void removeCookies();12 13 ...14 15 };
Many users want to execute these actions one by one, so the web browser can provide a function for this purpose:
1 class WebBrowser { 2 3 public: 4 5 ... 6 7 void clearEverything(); // calls clearCache, clearHistory, 8 9 // and removeCookies10 11 ...12 13 };
Of course, this function can also be provided through non-member functions, so that it can call the appropriate Member functions:
1 void clearBrowser(WebBrowser& wb) 2 3 { 4 5 wb.clearCache(); 6 7 wb.clearHistory(); 8 9 wb.removeCookies();10 11 }
Which method is better? Is the member function clearEverying or non-member function clearBrower?
2. Why are non-member non-friend functions good?
Object-oriented rules indicate that functions of data and operation data should be bundled together, which indicates that it recommends that member functions be a better choice. Unfortunately, this suggestion is incorrect. It misinterprets the meaning of object-oriented. Object-oriented rules indicate that data should be encapsulated as much as possible. The intuition is that the member function clearEverything is not actually better than the non-member function clearBrower.Better Encapsulation. Besides, non-member functions can be provided for web browsers.Larger Packaging(Packaging)Flexibility, Corresponding, you can generateLess compilation dependency and better scalability. Therefore, non-member functions are better than member functions in many aspects. Understand why it is important.
2.1 Non-member non-friends can generate more encapsulated classes
Start with encapsulation. If something is encapsulated, it means it is hidden. The more encapsulated things, the fewer customers can see them. Fewer customers can see them, which means we have more flexibility to modify them, because our modifications directly affect customers who can see these changes. As a result, the better encapsulation, we will be given more capabilities to modify it. This is why we put encapsulation first:It provides flexibility for us to modify things in a way that only affects a limited number of customers..
Consider the data associated with the same object.The less code (that is, access to it) the data is encapsulated, the better.We have more freedom to modify some features of the object's data, such as the number and type of data members. By checking how much code can see data to determine whether data encapsulation is a coarse-grained method, we can calculate the number of functions that can access data. The more functions that can access data, poor encapsulation.
Item 22 explains that data members should be private, because if not, unlimitedly a number of member functions can access them. In this way, there is no encapsulation at all. For private data members, the number of functions that can access them is the number of member functions in the class plus the number of friends functions, because only member functions and friends functions can access private members. Consider a member function (which can not only access private data of the category class, but also access private functions, enums, typedef, etc.) and a non-member non-friend function (neither private data nor functions can be accessed) and provide the same functions.To generate a larger encapsulation of non-member non-friend functions, because they did not increase the number of functions that can be used to sort private parts of the class.. This explains why clearBrower (non-member non-friend functions) is better than clearEverything: In the WebBrowser class, it produces a larger encapsulation.
There are two things to note at this point. First,This discussion is only applicable to non-member non-friend functions.. The same member function has the same access rights to private members of the class, so it has the same impact on encapsulation. From the perspective of encapsulation, it is not to select between a member and a non-member function, but between a member and a non-member function. (Encapsulation is not the only perspective of choice. Item 24 explains that in implicit type conversion, You must select between a member and a non-member function .)
The second thing to pay attention to is precisely because the function of the class is not a member function in encapsulation.It does not mean that this function cannot be a member function of another class.. We can declare clearBrower as a static member function of the utility class. As long as it is not part of WebBrowser (or a friend), it will not affect the encapsulation of private Members of WebBrower.
2.2 using non-member non-friends can reduce compilation Dependencies
In c ++, a more natural method isEnableClearBrowerBecome the same as WebBrowserNon-member functions with the same namespace:
1 namespace WebBrowserStuff {2 3 class WebBrowser { ... };4 5 void clearBrowser(WebBrowser& wb);6 7 ...8 9 }
It is not just more natural, because the namespace is not like a class, it can be cross-file. This is important because functions like clearBrower are very convenient. It is neither a member nor a friend, and has no special access to the WebBrower class. Therefore, it cannot provide any other functions that the WebBrowser client has not obtained. For example, if the clearBrower function does not exist, the customer has to call receivache, clearHistory, and removeCookies by themselves.
Classes such as webBrower can have a large number of convenience functions, some of which are related to tags, others are related to printing, and some are related to cookie management. Generally, most customers are only interested in some of them. There is no reason for customers interested only in tag convenience functions to compile convenience functions dependent on cookies. The direct way to separate them is to declare them in different header files.
1 // header “webbrowser.h” — header for class WebBrowser itself 2 3 // as well as “core” WebBrowser-related functionality 4 5 namespace WebBrowserStuff { 6 7 class WebBrowser { ... }; 8 9 ... // “core” related functionality, e.g.10 11 // non-member functions almost12 13 // all clients need14 15 }16 17 // header “webbrowserbookmarks.h”18 19 namespace WebBrowserStuff {20 21 ... // bookmark-related convenience22 23 } // functions24 25 // header “webbrowsercookies.h”26 27 namespace WebBrowserStuff {28 29 ... // cookie-related convenience30 31 } // functions
Note that the standard C ++ library is organized in this way. It does not include everything in a single <C ++ Stand Library> header file in the std namespace, but has many header files (<vector>, <algorithm>, <memory>, etc.). Each header file declares some functions in the std namespace. Customers who only use vector-related functions do not need to use # include <memory>. customers who do not need to use list do not need to use # include <list>.This allows customers to compile only the part that they actually use.. (Other methods for reducing compilation dependencies are discussed in Item 31 ). When a function comes from a member function of a class, it is impossible to split it, because a class must be defined in a whole. It can no longer be divided.
2.2 Non-member non-friends can provide better scalability
Placing all convenience functions in different header files-but in a namespace-also means that customers can easily expand convenience functions. What they need to do is to add more non-member non-friend functions to the namespace. For example, if a WebBrower decides to implement convenience functions related to image download, he only needs to create a header file and declare these functions in the namespace WebBrowserStuff. New functions can be integrated with them like old functions. This is another attribute that the class cannot provide, because the customer cannot extend the class definition. Of course, the customer can derive a new class, but the derived class does not have the permission to access the encapsulated members (such as private members) of the base class. Such an "Extension function" is a second-class identity. In addition, as explained in Item 7, not all classes are designed as base classes.