公共数据成员与 Getters,Setters

我目前在 Qt 和 C + + 工作。我的类具有私有数据成员和公共成员函数。我为类中可用的数据成员提供了公共 getter 和 setter。

现在我的问题是,如果我们的类中有数据成员的 getter 和 setter,那么将这些数据成员作为私有成员有什么意义呢?我同意在 Base 类中使用私有数据成员听起来是合乎逻辑的。但除此之外,拥有私人成员以及他们的 getter 和 setter 对我来说似乎并不合乎逻辑。

或者,我知道使用私有成员可以确保抽象化,但是使用 getter 和 setter 实际上可以非常容易地访问这些变量。任何关于这方面的建议都是受欢迎的。

37615 次浏览

Getters and Setters let you apply logic to the input/output from the private members therefore controlling access to the data (Encapsulation to those who know their OO terms).

Public variables leave your class' data open to the public for uncontrolled and non-validated manipulation which is almost always un-desirable.

You have to think about these things long term as well. You may not have validation now (which is why public variables seem to be a good idea) but there's a chance they'll be added down the road. Adding them ahead of time leaves the framework so there's less re-factoring down the raod not to mention the validation won't break dependent code this way).

Keep in mind, though, that doesn't mean Each and Every private variable needs its own getter/setter. Neil brings up a good point in his banking example that sometimes Getters/Setters just don't make sense.

If you have getters and setters for each of your data items, there is no point in making the data private. That's why having getters and setters for each of your data items is a bad idea. Consider the std::string class - it (probably) has ONE getter, the size() function, and no setters at all.

Or consider a BankAccount object - should we have SetBalance() setter to change the current balance? No, most banks won't thank you for implementing such a thing. Instead, we want something like ApplyTransaction( Transaction & tx ).

Make the data public. In the (rather unlikely) event that you do someday need logic in the "getter" or "setter", you can change the data type to a proxy class that overloads operator= and/or operator T (where T=whatever type you're using now) to implement the necessary logic.

Edit: the idea that controlling access to the data constitutes encapsulation is basically false. Encapsulation is about hiding the details of the implementation (in general!) not controlling access to data.

Encapsulation is complementary to abstraction: abstraction deals with the object's externally visible behavior, while encapsulation deals with hiding the details of how that behavior is implemented.

Using a getter or setter actually reduces the level of abstraction and exposes the implementation -- it requires client code to be aware that this particular class implements what is logically "data" as a pair of functions (the getter and setter). Using a proxy as I've suggested above provides real encapsulation -- except for one obscure corner case, it completely hides the fact that what is logically a piece of data is actually implemented via a pair of functions.

Of course, this needs to be kept in context: for some classes, "data" isn't a good abstraction at all. Generally speaking, if you can provide higher level operations instead of data, that's preferable. Nonetheless, there are classes for which the most usable abstraction is reading and writing data -- and when that's the case, the (abstracted) data should be made visible just like any other data. The fact that getting or setting the value may involve more than simple copying of bits is an implementation detail that should be hidden from the user.

Neither. You should have methods that do things. If one of those things happens to correspond with a specific internal variable that's great but there should be nothing that telegraphs this to the users of your class.

Private data is private so you can replace the implementation whenever you wish (and can do full rebuilds but that's a different issue). Once you let the Genie out of the bottle you will find it impossible to push it back in.

EDIT: Following a comment I made to another answer.

My point here is that you are asking the wrong question. There is no best practice with regard to using getters/setters or having public members. There is only what is best for your specific object and how it models some specific real world thing (or imaginary thing perhaps in the case of game).

Personally getters/setters are the lesser of two evils. Because once you start making getters/setters, people stop designing objects with a critical eye toward what data should be visible and what data should not. With public members it is even worse because the tendency becomes to make everything public.

Instead, examine what the object does and what it means for something to be that object. Then create methods that provide a natural interface into that object. It that natural interface involves exposing some internal properties using getters and setters so be it. But the important part is that you thought about it ahead of time and created the getters/setters for a design justified reason.

I suggest that you don't have public data members (except for POD structs). I also don't recommend that you have getters and setters for all of your data members. Rather, define a clean public interface for your class. This may include methods that get and/or set property values, and those properties may be implemented as member variables. But don't make getters and setters for all of your members.

The idea is that you separate your interface from your implementation, allowing you to modify the implementation without the users of the class having to change their code. If you expose everything through getters and setters, you've not improved anything over using public data.

The return value also effects the use of getters and setters. It's a difference to get the value of a variable or to get access to private data member variable. By-value keeps integrity, by-reference or by-pointer not so much.

On a strictly practical basis, I'd suggest you start by making all of your data members private, AND make their getters and setters private. As you find out what the rest of the world (i.e., your "(l)user community") actually needs, you can expose the appropriate getters and/or setters, or write appropriately-controlled public accessors.

Also (for Neil's benefit), during debugging time, it is sometimes useful to have a convenient place to hang debug prints, and other actions, when a particular data member is read or written. With getters and setters, this is easy. With public data members, it is a huge pain in the posterior.

If you are quite sure your logic is simple, and you never need to do something else when reading/writing a variable, it's better to keep the data public. In C++ case, I prefer to use struct instead of class to emphasize the fact that the data is public.

However, quite often you need to do some other things when accessing data members, or you want to give yourself freedom to add this logic later. In this case, getters and setters are good idea. Your change will be transparent to the clients of your code.

A simple example of additional functionality - you may want log a debug string every time you access a variable.

Aside from the encapsulation concerns (which are reason enough), it is very easy to set a breakpoint whenever the variable is set/accessed when you have getters/setters.

I've always thought that getters and setters are deliberately verbose in most programming languages specifically to make you think twice about using them - why does your caller need to know about the inner workings of your class should be the question at the front of your mind.

No, it is not even remotely the same thing.

There are different levels of protection/implementation hiding that can be achieved by different approaches to a class interface:


1. Public data member:

  • provides both read and write (if not const) access to the data member
  • exposes the fact that data object physically exists and is physically a member of this class (allows one to create pointers of pointer-to-member type to that data member)
  • provides lvalue access to the data member (allows one to create ordinary pointers to the member)


2. A method that returns a reference to a piece of data (possibly to a private data member):

  • provides both read and write (if not const) access to the data
  • exposes the fact that data object physically exists but does not expose that it is physically a member of this class (does not allow one to create pointers of pointer-to-member type to the data)
  • provides lvalue access to the data (allows one to create ordinary pointers to it)


3. Getter and/or setter methods (possibly accessing a private data member):

  • provides both read and/or write access to the property
  • does not expose the fact that data object physically exists, let alone physically present in this class (does not allow one to create pointers of pointer-to-member type to that data, or any kind of pointers for that matter)
  • does not provide lvalue access to the data (does not allow one to create ordinary pointers to it)

The getter/setter approach does not even expose the fact that the property is implemented by a physical object. I.e. there might be no physical data member behind the getter/setter pair.

Taking above into the account, it is strange to see someone claim that a getter and setter pair is the same as a public data member. In fact, they have nothing in common.

Of course, there are variations of each approach. A getter method, for example, might return a const reference to the data, which would place it somewhere between (2) and (3).

Using getters and setters will allow you to modify the way that you give the values to the user.

Consider the following:

double premium;
double tax;

You then write code all over the place using this premium value to get the premium:

double myPremium = class.premium;

Your specs just changed and premium from the user's standpoint needs to be premium + tax

You will have to modify everywhere that that premium value is being used in your code, and add tax to it.

If instead you implemented it as such:

double premium;
double tax;


double GetPremium(){return premium;};

All of your code would be using GetPremium() and your tax change would be one line:

double premium;
double tax;


double GetPremium(){return premium + tax;};

Getters and Setters exist primarily so that we can control how members are fetched, and how they are set. Getters and setters dont exist only as a way to access a specific member, but to ensure that before we try and set a member, that it perhaps meets certain conditions, or if we fetch it, we could control that we return a copy of that member in the case of a non-primitive type. Overall, you should try and use g/s'ers when you want to pipeline how a data member is to be interacted with, without them would cause the member is be used in an adhoc fashion.

Reasons to use public fields rather than getters and setters include:

  1. There are no illegal values.
  2. The client is expected to edit it.
  3. To be able to write things such as object.X.Y = Z.
  4. To making a strong promise that the value is just a value and there are no side-effects associated with it (and won't be in the future either).

Depending on what sort of software you work on, these might all be really exceptional cases (and if you think you've come across one you're probably wrong) or they might occur all the time. It really depends.

(From Ten Questions on Value-Based Programming.)

I believe that using getters and setters simply for getting and setting the value is useless. There is no difference between a public member and private one with such methods. Use getters and setters only when you need to control the values somehow or when you think that it might be useful in the future (adding some logic won't make you edit the rest of the code).

As a reference, read C++ guidelines (C.131)