So why should there be private member variables and methods at all?
A very compelling reason is interface. When member-variables are private, the class that owns them is responsible for changing their values. Consider a fraction class:
//Psuedo-code - not valid C++
class Fraction
{
public:
Fraction(const double num, const double denom); //Construction
print(); // prints out fraction "numerator/denominator
double value(); // get the value of this fraction as a double
double numerator;
double denominator;
};
In this instance, the class is merely a tuple binding two numeric values into a convenient package. A typical use might be:
Fraction f(2, 3); //two-thirds
Fraction g(1, 2); //One half
g.print();
// 1/2
Simple enough, I hope. Ideally, there would be operators to handle addition, subtraction, etc. What is significant about this class is that the numerator and denominator are held seperately in order to print as a fraction - which seems reasonable. The value of the class is not calculated until requested via the value() method.
Setting the value of this class in easy because the numerator and denominator are doubles, and because all the members of the class are public, we can just set the values directly. This is analagous to a C-style struct or a Python object.
f.numerator = 5;
f.denominator = 4;
f.print(); // Result: 5/4
So, everything is hunky dory. We can make fractions, set their values all day long. Damn, I'm happy.
Then one day, we realize that someone is setting the denominator as follows:
f.denominator(0.0); // oh, crap!
f.value(); //divide by zero!
Only they aren't just flat out setting it to 0.0, like an idiot, they are parsing some data from somewhere and, due to a parsing or rounding error, they are getting 0.0 in the denominator.
Now, the response on comp.lang.python would no doubt be "Duh! You are supposed to be a smart programmar! Check to see if your value is zero before you set it!" And they would be right, to a certain extent.
In practice, however, people are often rushed. They may have made a mistake deep inside some code, and didn't realize there was a condition in which this error could occur. Let's say they are setting the values of thousands of fractions in many different source files. They would never realize that the denominator was 0 until the value() function was called, in which case the run-time engine would probably throw an exception.
In such a case, let's also say that you adopt a policy that, if a user attempts to set the denominator to zero, it will instead be set to a very small double value.
But now you have code littered with 'f.denominator = x;' calls. These can't be intercepted because they are setting the value directly. How do you enforce this constraint on the object? You can do a global search and replace, but that is probably as tedious and error-prone as it sounds.
This all goes away with accessor methods and private variables. If I am designing this class, I can ensure that the class takes care of its own data. If I had a setDenominator function, it could decide what to do if someone sets bad data. It could throw an exception, make the data match the closest valid value, or just not change the data at all, depending on what I need it to do within the context of my application.
If I had used a setDenominator function, I would have this throughout my code:
f.setDenominator(2);
//Result: 5/2
I wouldn't have to go back through all the code and make sure that all explicit .denominator calls were valid. My setDenominator function would probably look like this:
setDenominator(double d)
{
if(d == 0)
d = .000001; //some small value approximating 0
*this.denominator = d;
}
In this way, I have used the interface to allow the object to manage its own data. The object can evaluate the data and take an appropriate course of action. This frees me from worrying about that everytime I need to set the denominator of an object and allows me to concentrate more on how I am going to use Fractions in my application.
I think this reason alone is justification for private variables and members. It's not that I don't trust that anyone using the class is a good programmer - even a junior programmer knows about divide by zero. The fact is, I am a busy programmer. I don't want to nursemaid every little part of a large class hierarchy if I can get the computer to do it for free. It takes a little more up-front work, but it can save alot of headache down the road.