Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Avoid Using Getters/Setters in C++?

Tags:

c++

I understand the reason why we should avoid using getters/setters, but I don't know how to avoid using them.

For example, I have three classes as follows,

  1. A (private: point_B)
  2. B (private: point_C)
  3. C (private: val_C)

A has a private member point_B which is a pointer that points to B, and B also has a private member point_C which is a pointer that points to C. And C has a private int value val_C.

How can I access val_C in A?

Update:

In this case,

  1. A is a class called state, which has the address point_B.
  2. B is a class called node, which has a pointer call pointer_C.
  3. C is a class called base_file, which has two derived classes called file and directory.

Update 2:

Ty guys for you help. Some of you are really trying to help instead of acting like someone who knows everything. I appreciate it. Sry I can't post the whole assignment here since its too large even without documents. I'll post professor's answer here if you guys are interested tomorrow.

Update 3:

Please find reference here The right thing to do is to leave the implementation to specify class.

Update 4:

The answer is to not to access private value in each class, but to implement functions to use them. That explains why making them private at the first place.

like image 852
Kevin217 Avatar asked Dec 10 '22 18:12

Kevin217


1 Answers

Maybe a little clarification is in order -- getters and setters aren't meant to be avoided at all costs; they have their place. The reason people say they should be avoided is because one goal of good object-oriented program design is encapsulation -- that is to say, each class should keep the details of its own implementation as private as possible, so that users of that class don't need to know (or care) about how the class was implemented. This becomes increasingly important as the program gets larger and more complicated, because a human programmer can only keep so many details in his/her head at once, and if the programmer has to remember everything about how class C works while simultaneously writing/debugging class A, that's an additional/unecessary cognitive burden that at some point will cause the programmer's brain to explode.

So, getting back to the main question -- how to avoid getters and setters -- the way to do it is to define your classes' interfaces at a higher level of abstraction than as simple repositories for state variables. (After all, if you wanted a simple collection of state variables, there's no reason to use a C++ class at all, you could simply declare a C-style struct instead)

For example, if your class C was intended to represent, say, a slot machine, a poor interface to class C might include lots of getters and setters, like this:

int getNumCoins() const {return numCoins;}
void setNumCoins(int newCoinCount) {numCounts = newCoinCount;}
void setDisplayedResult(const string & displayStr) {result = displayStr;}
int getDisplayedResult() const {return result;}

... and the poor programmer who was forced to use class C would have to write code like this:

playersWallet--;  // take a coin out of the player's wallet
c.setNumCoins(c.getNumCoins()+1);  // insert the coin into the machine
string newResult = "10 J A";   // somehow figure out what the machine should display
c.setDisplayedResult(newResult);  // and make the machine display it
if (c.getDisplayedResult() == "7 7 7")
{
   cout << "YOU ARE WINNER!" << endl;
   int numCoinsWon = 5000;  // jackpot!
   c.setNumCoins(c.getNumCoins()-numCoinsWon);  // deduct from machine's balance
   playersWallet += numCoinsWon;  // add to player's balance
}
[... and so on...]

Note that in the above code, the programmer had to think about all of the internal mechanisms of the slot machine, and write his own code to handle each step of its operation. With good encapsulation, on the other hand, the slot machine's public interface would be much simpler and more opaque, like this:

// returns the number of coins the player won on this round
int pullTheBigLever();

... and the programmer who was using this API might write code like this:

playersWallet += (c.pullTheBigLever() - 1);  // -1 for the coin the player put in

Note that there is only one line of code, and that the programmer didn't have to think at all about how the internals of the slot machine worked. This avoids exploding-programmer-brain-syndrome, and just as importantly it means you (or someone else) can go back later and change the private implementation of how the slot machine works without breaking the code that interacts with the slot machine.

So when are getters and setters acceptable? Answer: when there really isn't any higher level of abstraction to be had. If you are writing a class that represents a light switch, then just being able to examine the switch's current position, or specify a new position for it, may be all the functionality you need. But in many (most?) cases you are implementing the functionality of something more complex than that, and the more of that complexity you can hide behind your public interface, the happier users of that class (including you) will be.

like image 93
Jeremy Friesner Avatar answered Jan 02 '23 05:01

Jeremy Friesner