Why are get/set functions used in C++ so often?

Viewed 139

What is the point of doing this:

class thing {
    
public:
    void setMarbles(int _marbles){marbles = _marbles;}
    void getMarbles(){return marbles;}
    
private:
    int marbles;
};

when you can just do this:

class thing {
    
public:
    int marbles;

};

I feel like this is a super common question, but I cant find an answer anywhere. My only theory is that if the order ov variables are changed in a new version of the class, programs that are using the old class will have the variables switched. Is this the correct reason?

3 Answers

Encapsulation, maintainability, debugability

Consider:

void thing::setMarbles(int _marbles)
{
    // runtime error if incorrectly used
    assert(_marbles > 0);
    marbles = _marbles;
}

void thing::setMarbles(int _marbles)
{
    // log to some file to debug some specific scenario
    someLogUtility("Marbles write", _marbles);    
    marbles = _marbles;
}

You could also want to change thing in the future:

private:
char marbles; // support less marbles

or

private:
long marbles; // support more marbles

and then, you get to keep your setter without breaking external user code.

It is a really good practice, but it takes some mileage on real projects to see the full value. The short of it is: a public field ties your hands forever. A setter leaves flexibility.

Also, as suggested in comments:

void thing::setMarbles(int _marbles)
{
    // setting a breakpoint on next line is possible and lets you easily find where/when marbles is modified.
    marbles = _marbles;
}

It's a methodology of OOP. It cam from different culture that predates modern languages. It even predates C++. The idea is that you can hide how data is stored and accessed within those member functions.

Note that in C++ functions that are declared within class are considered inline. So writing

 thing a;
 a.setMarbles(4);

most likely generates same code as

 thing a;
 a.marbles = 4;

On other hand, if your marbles in future will be accessed from several threads, you easily can fix code by adding synchronization or change marbles to atomic by changing only thing class. In second case you have to fix every occurrence in your code.

If you later decide that you want to inject additional logic into getting/setting the value, those functions let you do it easily, without rewriting a bunch of code. This becomes proportionaly more important as your programs grow in size.

For example, you might want to check _marbles > 0 before changing the number.

If you're certain you'll never want this extra logic, yes, just make the field public.

Related