Why are member variables usually private?

hiya everyone.

In most of the sample code I see, classes are defined something like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class A
{
  private:
    int x,y;
    char theChar;

  public:
    Foo();
    ~Foo();
    void doCoolStuff();

    int get_x()  {return x;}
    int get_y()  {return y;}
    char get_theChar() {return theChar;}
};


Then later they're like
1
2
3
4
A bar;

cout<<"bar's x: "<<bar.get_x()<<endl;
//etc... 


so what is the point of doing that.. why not just do
cout<<"bar's x: "<<bar.x<<endl;

of course the x variable would have to be public to do that... but that would be easy to remedy...

Soo why is it usually done with the former method??

Last edited on
For two reasons: the member might need to be read-only, as it seems to be in your example, or there may be some other actions that need to be performed each time the variable is read or written.

It's not unusual, though, to see people that don't understand how to properly use interfaces, and instead of only writing them for those members that do need them, they wrap ALL members with interfaces that do nothing other than set or get the members. This is a waste of human time, a waste of CPU time, a waste of memory, and a waste of source code space (all that useless garbage can make reading a source a real pain).
Why don't you put your government ID number on the internet? (Here in the US that's the Social Security number.)

Why don't video games let the user decide whether or not he won? Or how many points he gets?

Remember things like the Game Genie? Plug your game cartridge in one end and attach the other to your SNES or Genesis console, and be indestructible, etc. The difficulty and proper functioning of the game is subverted. (Ever notice how much more likely the game is to crash when it is plugged into a Game Genie? Part of their advertising is the care they took to minimize such occasions.) For a game, not a big deal.

What about banks and your checking account balance. Suppose Joe Green in Montana were to have the power to change the amount of money listed under your name. Suppose you had the power to change the amount of money listed under your name.


A class is, for all intents and purposes, a closed system. Just like your car. You turn the steering wheel, which turns the steering shaft, which turns the pinion that slides the rack left or right, which turn the wheels.

Suppose your son/daughter/spouse/neighbor decides that rack and pinion is old hat, and instead thinks that your car works (or ought to work) with recirculating-ball linkage. So he/she/it/whatever gets his toolset and goes under the hood and adjusts the tie rods (linking the track rods to the wheels) appropriate for the recirculating-ball.

You get back into the car and try to drive somewhere and the steering wheel doesn't turn the wheels the same way. Your car is out of balance. The inner tread on the wheels wears out quickly, and the car "binds" in tight turns.

This all happened because someone who should have known better reached into your car's internals and changed things he shouldn't.


The very same is true of classes. A class is a self-contained black box. On that black box are buttons and widgets you can press and turn and the like to get various lights to blink the right way. But the instant you assume you know the internal workings of that black box, you break the abstraction and limit its usefulness.


For this reason I disagree with helios. It is not a waste to do things the right way. By taking a few minutes to add getter/setter methods to a class you have made your classes extensible and saved your company countless thousands in mantenance costs. (It doesn't cost anything in CPU time --inlined functions make direct accesses, and even if otherwise procedure jumps cost a lot less than people are taught to believe.)

The whole purpose of an interface is to define how a thing appears. But underneath things may change, depending on the system in which the object works, or optimizations for different inputs, or modifications in the product lifecycle.


Iff the interface provides a simple variable access, then leave it as a simple variable access. Otherwise, use an accessor. A good example is a CSV file class I recently wrote. Not all CSV files are equal. Two interesting features are as follows:

Record Separator (RS): this is typically the newline sequence used on your platform: CR on Mac, CRLF on Windows, LF on Unix. As a matter of being consistent, the CSV class needed to recognize what the input RS is. But, you also have the option to modify what is used on output. But the user of the class doesn't care about all the machinery inside necessary to make this work. All he cares is that "I want it to write the same as it read", or "I want it to write what my system's default is, no matter what the input was", or "I want my Mac-freak boss to be able to read it". The machinery is tucked behind the get/set accessors of the class.

Field Delimiter (FD) and Quote Character (QC): these are optional characters used to "quote" field data. (Remember, CSV files are not textual; any type of data --even binary-- can be stored in the fields.) For this to happen, a FD is required. But in many, if not most, cases, it is unnecessary. Moreover, it is possible that one exist without the other, or other weird permutations. Again, the machinery that handles all this is not the concern of the user. All he wants is to be able to say: "this CSV file uses the double-quote character as he Field Delimiter and the following N symbols as Quoted Characters. Hence, the setter/getter member functions hide all those ugly details.

In reality, they are each just an int. But what if I improve it? What if I give it better powers? Or what if I widen the operational requirements? The accessor methods allow any improvements I make to continue to work with old code, instead of having to add a new comconnosant class to get around the original error (this splinters the code base) or have to hunt and peck to find all instances where the original code was used and fix it (which inevitably introduces bugs and/or redevelopment time).

Employees really don't have any right to waste their employer's time and money. Do it correctly from the beginning.


I know it is obnoxious to code classes in C++. The language is not designed to be easy for class writers. It is designed to make life easy for the users of the class. The poor saps writing the class have a lot of work to do to make that happen.


But, in the end, it depends entirely on the scope and purpose of the class itself. Don't do what is easy. Do what is correct for the assignment.

Hope this helps. (and sorry for the long lecture)
Wow. Now I get it. That was a good lecture, Duoas.
O_O

I'm honored by the massive lecture..

...so are you basically saying that it's better to have [gs]etter methods so u can improve stuff later without finding everytime u [gs]et the variable...? Isn't that the general philosophy behind functions anyway?

pretty neat... thanks.

tho i feel obligated to point out that knowing how a car works does not undermine its ability.. and the same goes for classes, doesn't it? Even if I wrote the class myself and know that the get_avgSpeed method is just dividing the distance by the time... that doesn't make it any less useful... does it? Maybe I missed your point when you said "the instant you assume you know the internal workings of that black box, you break the abstraction and limit its usefulness."

care to elaborate?
Whew. That was pretty long. Sorry if I'm repeating something you already said, but I can't read all that.

I do agree with Duoas that data hiding should be used when your classes are expected to be used by other people. But let's face it. Most of the classes you write will be internal classes for your programs and you'll be the one using them.
If interfaces are supposed to make it easier for the user of the class, then using them in your own programs (this is something I forgot to mention earlier) when they aren't necessary is counter-productive. You're just adding red tape to something that could otherwise be a pretty straightforward process.
Generally speaking a lot of getter/setter methods is a sign of improper OO design for two reasons:

1) Getter methods expose internal implementation of your class.
vector<int> getList() const { return myList; }
The user of your class now knows that your class implements the list via vector.
Now you, as the programmer of the class, are stuck using a vector essentially
forevermore, even though you might find later that a deque or set would have been
a better choice.

2) Every object has its own "state" which is reflected by the values of all of its
member variables. For example your class might have a vector<int> myList
member and an int highest member that stores the highest value of all the
ints in the vector. Allowing the user to modify the class' internal state is
basically saying that the state is really external, and the user somehow can
know better how to manage it than the class. Basically it goes back to Duoas'
statement that a class is (should be) a closed system.

Now sometimes getters are unavoidable, so I'm not saying you should never use
them. But you should minimize their use.
Agreed and Agreed.

:-]
jsmith, I disagree.

The point of getter / setter methods is that there is a degree of separation between the external and internal.

given

vector<int> getList() const;

this means that the external representation is fixed as a vector <int>.
As the author of the class you are free to change the internal representation - you just have to provide an appropriate implementation of getList() to transform your choice to a vector <int>

Of course, the question of should you be exposing the list, and if it should have a getter, setter or both is a different question and always providing getters and setters for everything is a sign of poor design.
Beautiful, I feel enlightened by the level of education I just received. Thank You all for your hard work.

So if I am not mistaken, use gs functions where another person will be using the class, otherwise your safe skipping them if its just you and your own programs going through them.
I think what jsmith is talking about is simply exposing the internals via accessor methods. This is a bad design. Duncan's original example is obviously contrived, but it is sadly not too uncommon to see such things.

Accessors should provide information about the object, not its internal structure (which is Faldrax's point). Sometimes that information really is a direct read of an internal variable, sometimes it is not. But what is dangerous is when the interface (accessor methods) are nothing more than a list of things that are inside the box.

Umz, I would amend that to:
Always use accessor methods unless you can reasonably prove to yourself (or development team) that the object itself is private (not used outside of a small, specific context --e.g. a single .cpp file).
I think i get it. So a better example is like this:

1
2
3
4
5
6
7
8
9
10
class Car
{
  private:
    int vel;
    int travelTime;
    int mass;
  public:
    int getDistance()  {return (vel*travelTime);}
    int getMomentum()  {return (mass*vel);}
};


pretty neat.
Yes, that would be a good example, although you will probably want setter/getter methods in addition (unless you don't plan on doing anything else with Car...but even then)
Topic archived. No new replies allowed.