开发者

Private set / get functions -- Why private and how to use?

开发者 https://www.devze.com 2023-03-30 12:12 出处:网络
I\'ve read a lot of guides that explain why I should use \"private\" and the answer is always \"Because we don\'t want anyone else setting this as something\".So, let me ask the following questions:

I've read a lot of guides that explain why I should use "private" and the answer is always "Because we don't want anyone else setting this as something". So, let me ask the following questions:

Assuming that I want to have a variable that is set-once (perhaps something like a character name in a video game, ask once, then it's set, and then you just use the get variable(edit:function) for the rest of the game) how do I handle that one set? How would I handle the get for this as well?

What is the actual advantage of using a private access modifier in this case? I开发者_C百科f I never prompt the user to enter the name again, and never store information back to class.name shouldn't the data remain safe (moderately, assuming code works as intended) anyways?

I hope someone will help me out with this as the explanations I've googled and seen on here have not quite put my thoughts to rest.

Thanks!


The access specifiers mainly serve to denote the class interface, not to effectively limit the programmer's access or protect things. They serve to prevent accidental hacking.

If something is set once, then you should try to set it when it is created, and make it const.

If the interface doesn't need to be especially clear (for example, if few people need to learn it) then it doesn't make sense to spend effort engineering it. Moreover changes that don't make much difference in how the interface is used can be applied later. The exposed variable can be changed to a getter/setter using simple search-and-replace.

If it were a published binary interface, then you would want to get it right the first time. But you're just talking about the internals of your program.

And it's fairly unlikely that anyone will reset the player name by accident.


I won't try to justify the private set method as that sounds a bit weird to me. You could handle the one set by using a friend declaration. But then why would you define a setter when the friend could just set the value directly?

I generally avoid setters if I can at all manage it. Instead I prefer provide facility to set member variables via the constructor. I am quite happy to provide getters if they make sense.

class player_character_t {
    std::string name_;
public:
    player_character_t(std::string const& name)
    :   name_ (name)
    {
    }

    std::string const& name() const { return name_; }
};

This forces you to delay construction of the object until you have all the information you require. It simplifies the logic of your objects (ie they have a trivial state diagram) and means you never have to check is something is set before reading it (if the object exists, it is set properly).

http://en.wikipedia.org/wiki/State_diagram

Marking things as private helps prevent accidents. So when you make a mistake and it is no longer the case that the "code works as intended" the compiler may help you detect it. Likewise const can be a big help in detecting when you are using objects incorrectly.


It's that last parenthetical that is important: assuming code works as intended.

In my mind it's similar to permissions in Linux systems. You know the root password and you can delete any file, but you don't stay logged in as root so you don't do anything by accident. Similarly, when you have a private variable characterNameString, and someone (or you) later tries to give it a new value, it will fail. That person will have to go look at the code and see that it's marked private. That person will have to ask themselves "why is this private? Should I be modifying it? Should I be doing this another way?" If they decide they want to, then, they can. But it prevents silly mistakes.


Don't confuse the private and the public interfaces of the class. In theory these are completely different interfaces, and this is just a design feature of C++ that they're located physically in the same class declaration.

It's perfectly ok to have a public getter/setter when the object property should be exposed via the public interface, so there is no rule such as 'setter is always private'.

More on that topic in the (More) Exceptional C++ books by Herb Sutter. It's an absolutely neccessary reading for someone who wants to understand C++ and be proficient with it.

If you have doubts over deciding whether to use getter/setters over the class variables, there are numerous explanations on the internet why getters/setters are better.


If the variable is 'write once then forever read only' I'd recommend making it a const member that is initialized during construction. There's no value in a private 'setter' function because it won't be used. Also you avoid people using the setter function to set the name when it's never meant to be set.

For example:

class Player
{
  private:
    const std::string m_name;

  public:
    Player(const std::string& name) : m_name(name) {}
 };


Private getters and setters all make sense when the data in question involves several variables, have additional constraints you want to make sure you adhere to, and these operations are done several times in your class. Or when you plan further modifications to the data model and wish to abstract operations on the data, like using std::vector but planning to make it std::map or similar cases.

For a personal example, I have a smart pointer implementation with a private reset(T*, int*) method that is essentially a setter for the stored object and its reference count. It handles checking validity of objects and reference counts, incrementing and decrementing reference counts, and deleting objects and reference counts. It is called eight times in the class, so it made perfect sense to put it into a method instead of just screwing around with member variables each time, slowing programming, bloating code and risking errors in the process.

I am sure private getters can also make sense if you are abstracting the data from the model and/or you have to implement error checking, for example throwing instructions if the data is NULL instead of returning NULL.

0

精彩评论

暂无评论...
验证码 换一张
取 消