Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do people write private-field getters returning a non-const reference?

We can all agree on public variables being bad for encapsulation and all that. However, I noticed a lot of code that does this type of stuff:

class foo {
private:
    int integer_;
    string someString_;
    // other variables
public:
    int& integer() { return integer_; }
    string& someString() { return someString_; }
    // other "functions"
}

int main() {
    foo f;
    f.integer() = 10;
    f.someString() = "something";
    return 0;
}

I have seen this being used in many places and I don't get why. Basically it returns a reference to the data and thus exposes it directly to the outside. So encapsulation is not really achieved, not from any perspective.

Why is this commonly used?

like image 953
Everyone Avatar asked Mar 03 '17 19:03

Everyone


2 Answers

There's a recurring mantra, that getter/setter functions should be used to encapsulate your data. Hence many (unexperienced or coffee-overloaded) programmers get the idea they should use something like:

int& integer() { return integer_; }

but that isn't much different from simply writing:

class foo {
public: // <<<
    int integer_;
    string someString_;
    // ...
};

Well, it adds a function call, but you cannot control what the client does with the reference.


If you really want to provide a getter function write:

const int& integer() const { return integer_; }

A corresponding setter function looks like:

void integer(const int& value) {
    integer_ = value;
}
like image 76
πάντα ῥεῖ Avatar answered Oct 22 '22 01:10

πάντα ῥεῖ


I have to partially disagree both with @πάνταῥεῖ and @Rakete1111 's answers, considering how a class's definition is something that may evolve over time.

While it's true that, often, these getter methods are written by someone who's just heard the "no exposing members" mantra, they can also have legitimate uses:

  1. The getter method may later be modified to include some kind of validity check or resource allocation code before returning the reference - which direct access to the data member does not allow. While this means changing the class's code, it does not require changing the class user code. Also, if the implementation of the getter is not exposed in the class header, it might not even require recompiling the class user code. Note: Doing so is probably a sign of some other poor design choice.
  2. The getter method may be overridden by a subclass (in which case it is often made a virtual method) in a similar way to the above.
  3. The getter method may later replace its return type with a proxy for the original data member type, rather than a reference to an actual member - which may no longer even exist. Think of how vector<bool> works; when you call its operator[] you don't get a boolean&, you get some kind of proxy which, when assigned or assigned-to, does the appropriate bit extraction or setting.
  4. A non-const getter is not usable for non-const instances. So actually it does limit access relative to exposing the member outright. Whether the author of OP's example class actually intended this is a different question...

To sum up: The "dummy" non-const-reference getter can be a stub for other, meaningful, code.

That being said, it is often a good idea to just make the getter return a const reference or a value. Or just exposing the field in those cases where it's appropriate (and there are some of those too).

like image 30
einpoklum Avatar answered Oct 22 '22 02:10

einpoklum