Do I need accessors and mutators for every class variable?

Started by
18 comments, last by StoneMask 11 years, 8 months ago
I understand the importance of keeping some data members from being accidentally manipulated outside class functions, but say I have a class object that's full of variables I need to check up on all the time, like the player in a video game. Is it really worth it to make the program jump control between those functions all the time? What are the criteria for a variable that's worth making an accessor/mutator function? Because so far, this is what my character's header looks like:

[spoiler]/* mutators */
void AddLevel (short alteration);
void AddHealth (short alteration);
void AddExP (short alteration);
void AddKeys (short alteration);
void AddTorches(short alteration);
void AddGems (short alteration);
void SetFacing (short alteration);
void SetExP (short alteration);
void SetPosX (short alteration);
void SetPosY (short alteration);
void SetIsHurt (short posX, short posY, bool isBoss);
void SetInFort (bool alteration);
void SetInShop (bool alteration);
void SetInSpace (bool alteration);
void SetFasT (bool alteration);
void SetGoldWhale(bool alteration);
void SetWin ();
void SetmFufni();
void SetName ();
/* accessors */
short GetLevel();
short GetHealth();
short GetExP();
short GetKeys();
short GetTorches();
short GetGems();
string GetName();
short GetFacing();
short GetPosX();
short GetPosY();
bool GetTorch();
short GetTorchX();
short GetTorchY();
char GetInFront();
bool GetInFort();
bool GetInShop();
bool GetInSpace();
bool GetFasT();
bool GetIsHurt();
bool GetSetting();
bool GetWin();
COORD GetPos();
[/spoiler]

I'm running out of stuff to name these things, and sometimes I have to work around just naming it something I think is clear enough.
Advertisement
Empty accessors and mutators are a code smell.

If you need to do some logic that ensures that the class's invariants are upheld when changing a variable, go ahead and wrap it in this way. Otherwise, if modifying the variable arbitrarily can't break the class from the outside, just use public member data.

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]

What do you mean? Wouldn't that mean just any variable that's actually changed? How do you define arbitrary when modifying something? Or breaking the class from the outside, for that matter?
Performance is not really an issue, specially if you pass variables bigger then a single datatype as const reference, getters will usually be inlined by the compiler and will compile into the same code as if you would access the variable. However, you shouldn't have classes with tons of setters and getters, having to many of them is probably a sign your class has to many responsibilities and needs to be split into multiple classes, or that it has to little responsibilities (which is possible as well if you are using your class as a struct rather then object). Personally I try to avoid setters that refer to a specific variable, as that would mean the object who calls it has to know how this class works internally. Instead, I prefer to have functions that invoke a specific state change or give me the information I need. Just like in real life, if you buy a plane ticket you ask for a plane ticket to the destination you want to go, you don't ask the person behind the desk to take form C13, put it in the printer, type in your destionation and hit print. Basically you tell what you want to be done, not how you want it to be done.
Could you give me an example of something that would need subdividing into multiple classes, and how to implement it so you can still access all the information of the other class?
Getting a bit away from your specific question, I'd caution that part of the problem is that you're beginning to have a rather monolithic, unfocused class.

It's difficult to say without knowing more about the design of the game itself, but the impression that the accessor/mutator names give me is that some of them could stand to be combined into their own class (For example: posX, PosY, and [maybe] Direction might become a class) and others either seem to be misplaced (InFront, InFort, InShop, InSpace) and/or might indicate some kind related state that could be expressed as an enumeration (if states are mutually exclusive or have limited but well-known combinations) or a bitfield (if states can be combined more freely).

Still others might be better solved in a much more general fashion, for example you have a number of variables that seem to track inventory -- if the variety of available inventory items is small this approach may be fine, but if the varieties grow to more than a couple of handfuls, you might want to look into creating an inventory object that holds the actual items, and having this "player" class have an inventory (either directly, or by owning a unique key within a shared inventory system). In short, as you add more variety of items, you tend to want something that starts to look more and more like a database, rather than an ad-hoc collection of values. You can do stats similarly.

Basically, try to think about the different contexts in which you currently plan to access your "player" class, and see how the data naturally groups together -- for example, its unlikely that a single context would care about the player position *and* the contents of their inventory simultaneously, in a well-designed system.

throw table_exception("(? ???)? ? ???");

I made this project under a deadline and I just kind of added stuff and didn't plan anything out. The state of where the character is in the environment could definitely be an enumeration, now that I think about it. I have other enumerations in the class.

The character's inventory really only has two things in it. The game is very simple.

So you're all recommending that I make some of these things structs or classes and have the getters of my player class just return one of the values depending on the states in those structs or classes? As a cleanliness question, would I want to put the classes that are used solely for other classes in their own .h/.cpp files?
How do you mean 'used solely for other classes'? Like you have class A and class B and class A is the only class that uses class B? If that's what you mean then one option is to nest class B within class A. Here's some more information.

C++: A Dialog | C++0x Features: Part1 (lambdas, auto, static_assert) , Part 2 (rvalue references) , Part 3 (decltype) | Write Games | Fix Your Timestep!


What do you mean? Wouldn't that mean just any variable that's actually changed? How do you define arbitrary when modifying something? Or breaking the class from the outside, for that matter?


For example, suppose you have a class that represents a book that you can write in. That class has a variable "NumWrittenPages" which tells you how many pages have been written in. It also has a function "WriteOnPage" which increments the NumWrittenPages variable.

Now; suppose some other code just goes and sets NumWrittenPages to some new number, without calling WriteOnPage. This would "break" the class in the sense that the object no longer correctly reflects reality. If WriteOnPage depends on the value of NumWrittenPages, this is probably a bug waiting to happen.

In that case, you want to use an accessor for NumWrittenPages, but not provide a mutator.


Or you might have a NormalizedVector class, which expects that its length is always 1. Modifying its x, y, and z coordinates directly is a recipe for disaster, because external code can make the length change to anything. So you wouldn't make them public. However, you might want to support setting the vector up all at once, such as Set(x, y, z). In that case, you simply implement Set() so that it re-normalizes the vector regardless of what the input numbers are. This ensures that the class invariant (i.e. the vector is length 1) is never violated.


In cases like this where you need to ensure something doesn't break when you set new variable values, mutators are OK. If you don't need limitations like that, just use public member variables.

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]

Here's an idea for you: "void AddToCharacteristic( CharacteristicType type, int value );"

This topic is closed to new replies.

Advertisement