Consider this scenario: we have a Computer class, and every time we shut down the computer, we need to execute the steps of closing all applications, shutting down, and powering off:
class Computer{public: ... // Close all applications void closeAllApps() { ... } // Execute shutdown void shutdown() { ... } // Power off void powerOff() { ... } ...};
At this point, it is necessary to write a convenient function to shut down the computer, which will perform these three actions. This function can be a member function or a non-member function:
class Computer{public: ... // Shut down the computer -- member function approach void closeComputer(){ closeAllApps(); shutdown(); powerOff(); } ...};// Shut down the computer -- non-member function approachvoid closeComputer(Computer& computer){ computer.closeAllApps(); computer.shutdown(); computer.powerOff();}
We face a choice: should this function be written as a member function? My answer is: no.1. From the perspective of encapsulationThe encapsulation of the non-member function approach is better. Indeed, it is the non-member function approach. Here, it is important to explain that encapsulation is not simply about placing functionality within a class.Encapsulation means that the client cannot see or use it. Only in this way do we have greater flexibility to modify. The non-member function approach exposes less, while member functions (including friend functions) can see more within the class, thus the non-member function approach has better encapsulation.Additionally, the non-member function here refers to a function that is not a member of this class; it can also be a member function of another class.2. Better extensibility and lower compilation dependencyOur general practice is to place the non-member function closeComputer in the same namespace as the Computer class.The benefit of this approach is that namespaces can span multiple files. When clients want to extend their convenience functions, they only need to include a header file for this namespace.On the other hand, we can separate different convenience functions into different header files, allowing users to include only what they need, thereby reducing compilation dependencies.