Item 22: declare data members as private
By Scott Meyers
Translator: fatalerror99 (itepub's nirvana)
Release: http://blog.csdn.net/fatalerror99/
Now, let's announce the plan. First, let's see why data members (data members) should not be public. Then, we will see that all the reasons against public data members (public data members) also apply to protected (protected. This exports the conclusion that data members (data member) should be private (private). So far, we are finished.
So, public data members (public data member), why not?
We start with the syntax consistency (see item 18 ). If data members (data member) is not public, the only way for a customer to access an object is through member functions (member function ). If everything in a public interface is a function, you don't have to worry about whether to use parentheses when they want to access a class member. They only need to use it, because everything is a function. Sticking to this policy for a lifetime can save a lot of time scratching your head.
However, you may not think that the reason for consistency is mandatory. What about the fact that using functions allows you to more accurately control the accessibility of data members (data members? If you set a data member (data member) to public, everyone can read-write access to it, however, if you use a function to obtain and set its value, you can implement no access (Access prohibited), read-only access (read-only access) and read-write access ). Further, if you need to, you can even implement write-only access (write-only access ):
Class accesslevels {
Public:
...
Int getreadonly () const {return readonly ;}
Void setreadwrite (INT value) {readwrite = value ;}
Int getreadwrite () const {return readwrite ;}
Void setwriteonly (INT value) {writeonly = value ;}
PRIVATE:
Int noaccess; // no access to this int
Int readonly; // read-only access to this int
Int readwrite; // read-write access to this int
Int writeonly; // write-only access to this int
};
This hierarchical access control is very important because many data members (data members)Shocould(Should) be hidden. It is rare that each data member (data member) needs a getter and a setter.
Don't you believe it? So it's time to come up with a heavy gun: encapsulation (encapsulation ). If you use a function to access a data member (data member), you can replace the data member (data member) with a calculation later ), people using your class will not notice anything.
For example, suppose you write an application for an automatic device to monitor the speed of a vehicle that passes through. Every time a car passes through, its speed is calculated, and that value is added to the collection of all the speed data collected so far:
Class speeddatacollection {
...
Public:
Void addvalue (INT speed); // Add a new data value
Double averagesofar () const; // return average speed
...
};
Now consider the implementation of member function (member function) averagesofar: One way to implement it is to use a data member (data member) in the class) to change the average value of all the speed data collected so far in real time. Whenever averagesofar is called, it only returns the value of the data member (data member. Another different method is to re-calculate the value of averagesofar every time you call it. It can do this by checking every data value in the set.
The first method (to maintain an average value of real-time changes) makes every speeddatacollection object large, because you must hold the average value of real-time changes, data members (data members) that accumulate sum and the number of data points are allocated space. However, averagesofar can be very efficient now. It is just an inline function that returns the average value of real-time changes (see item 30 ). In turn, the average value is calculated whenever the request is made, making averagesofar run slowly, but every speeddatacollection object is relatively small.
Who can say which one is the best? It may be a good solution to calculate the average value every time on a machine with very tight memory (such as an embedded roadside device) and an application with very few average values. In an application that frequently requires an average value, speed is a basic requirement, and memory is not a problem. It is more desirable to maintain an average value of real-time variation. The focus here is to use a member function (member function) to access the average value (that is, by encapsulating it ), you can swap these two different implementations (and other implementations you may think of). For customers, at most, they must be re-compiled. (You can use the technology described in item 31 to solve this problem .)
Hiding data members (data members) in functional interfaces can provide mobility for various implementations. For example, it can easily report other objects when data members (data members) are read or written. It can verify class invariants (class constants) and the Front and back conditions of functions, you can execute synchronization tasks in a multi-threaded environment. Programmers who come to C ++ from languages similar to Delphi and C # will agree with the function of such equivalents similar to "properties" ("attribute") in those languages, although an additional pair of parentheses is required.
The encapsulation (encapsulation) may be more important than it was initially revealed. If you hide your data members (data members) (that is, encapsulate them) to your customers, you can ensure that the class invariants (class constants) are always maintained, because only member functions (member functions) can affect them. In addition, you reserve the right to change your decision-making in the future. If you do not hide such a decision, you will soon find that even if you have the source code of a class, your ability to change anything public is extremely limited, because too many customer code will be destroyed. Public means that it is not encapsulated. In fact, unencapsulated means that it cannot be changed, especially the widely used classes. However, most of the widely used classes use encapsulation, because they can maximize the benefits of replacing existing implementations with a better implementation.
The reasons against protected data members are similar. In fact, it is the same, although it does not seem so at first. Obviously, the arguments about syntax consistency and bar-based access control can be applied to protected data like public, but what about encapsulation (encapsulation? Is protected data members more encapsulated than public? To be honest, the surprising answer is that they are not.
Item 23 explains that if something changes, the encapsulation (encapsulation) of something is inversely proportional to the number of code that may be corrupted. Therefore, if a data member (data member) changes, for example, if it is removed from the class (probably to support computing, just like in the averagesofar above ), the encapsulatedness (encapsulation) of this data member (data member) is inversely proportional to the number of code that may be corrupted.
Suppose we have a public data member (a public data member), and then we exclude it. How much code will be destroyed? All customer code that uses it, the number of which is usuallyUnknowably large(Incredible ). Therefore, public data members is completely unencapsulated. However, suppose we have a protected data member (protected data member), and then we exclude it. How much code will be destroyed now? All the derived classes (derived class) that use it. In typical cases, the number of codes isUnknowably large(Incredible ). Therefore, protected data member (protected data member) is not encapsulated like public, because in both cases, if data members (data member) changes, the number of corrupted client code is unknowably large (incredible ). This is not intuitive, but experienced database implementers will tell you that this is true. Once you declare a data member (data member) as public or protected, and the customer starts to use it, it is difficult to change anything related to this data member (data member. Too many codes have to be rewritten, retested, redocumented, or re-compiled. From the perspective of encapsulation (encapsulation), there are actually only two access layers: Private (providing encapsulation (encapsulation) and all others (not provided ).
Things to remember
- Declare data members as private. It provides customers with syntactically consistent access to data, provides access control by Bar Analysis, allows the immutability to be forced, and provides implementation mobility for class authors.
- Protected is not more encapsulated than public.