Effective C++, 2E | Item 20: Avoid data members in the public interface Back to Item 19: Differentiate among member functions, non-member functions, and friend functions. Continue to Item 21: Use const whenever possible. Item 20: Avoid data members in the public interface. First, let's look at this issue from the point of view of consistency. If everything in the public interface is a function, clients of your class won't have to scratch their heads trying to remember whether to use parentheses when they want to access a member of your class. They'll just do it, because everything is a function. Over the course of a lifetime, that can save a lot of head scratching. You don't buy the consistency argument? How about the fact that using functions gives you much more precise control over the accessibility of data members? If you make a data member public, everybody has read/write access to it, but if you use functions to get and set its value, you can implement no access, read-only access, and read-write access. Heck, you can even implement write-only access if you want to: 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 }; Still not convinced? Then it's time to bring out the big gun: functional abstraction. If you implement access to a data member through a function, you can later replace the data member with a computation, and nobody using your class will be any the wiser. For example, suppose you are writing an application in which some automated equipment is monitoring the speed of passing cars. As each car passes, its speed is computed, and the value is added to a 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 the member function averageSoFar (see also Item M18). One way to implement it is to have a data member in the class that is a running average of all the speed data so far collected. Whenever averageSoFar is called, it just returns the value of that data member. A different approach is to have averageSoFar compute its value anew each time it's called, something it could do by examining each data value in the collection. (For a more general discussion of these two approaches, see Items M17 and M18.) The first approach keeping a running average makes each SpeedDataCollection object bigger, because you have to allocate space for the data member holding the running average. However, averageSoFar can be implemented very efficiently; it's just an inline function (see Item 33) that returns the value of the data member. Conversely, computing the average whenever it's requested will make averageSoFar run slower, but each SpeedDataCollection object will be smaller. Who's to say which is best? On a machine where memory is tight, and in an application where averages are needed only infrequently, computing the average each time is a better solution. In an application where averages are needed frequently, speed is of the essence, and memory is not an issue, keeping a running average is preferable. The important point is that by accessing the average through a member function, you can use either implementation, a valuable source of flexibility that you wouldn't have if you made a decision to include the running average data member in the public interface. The upshot of all this is that you're just asking for trouble by putting data members in the public interface, so play it safe by hiding all your data members behind a wall of functional abstraction. If you do it now, we'll throw in consistency and fine-grained access control at no extra cost! Back to Item 19: Differentiate among member functions, non-member functions, and friend functions. Continue to Item 21: Use const whenever possible.