C++ 公共数据成员 vs Getter、Setter

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2977007/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 11:39:28  来源:igfitidea点击:

Public Data members vs Getters, Setters

c++settergetter

提问by liaK

I am currently working in Qt and so C++. I am having classes that has private data members and public member functions. I have public getters and setters for the data members available in the class.

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

Now my question is, if we have getters and setters for data members in our classes then what's the point in making those data members as private?I agree having private data members in Base classes sounds logical. But besides that, having private members and so do their getters and setters doesn't seem to be of a logical one for me.

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

Or instead can we make all variables as public so that no need for getters and setters at all? Is it a good practice to have those?I know having private members ensure data abstraction but having getters and setters actually lets access to those variables quite easily. Any pointers regarding this are welcome.

或者我们可以将所有变量设为公共变量,这样根本不需要 getter 和 setter 吗?拥有这些是一个好习惯吗?我知道拥有私有成员可以确保数据抽象,但拥有 getter 和 setter 实际上可以很容易地访问这些变量。欢迎任何有关这方面的指示。

回答by jmucchiello

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).

我的观点是你问错了问题。在使用 getter/setter 或拥有公共成员方面没有最佳实践。只有最适合您的特定对象以及它如何模拟某些特定的现实世界事物(或在游戏中可能是想象的事物)。

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.

个人 getter/setter 是两害相权取其轻的。因为一旦你开始制作 getter/setter,人们就不再以批判的眼光来设计对象了,哪些数据应该是可见的,哪些数据不应该是可见的。对于公共成员,情况更糟,因为倾向于将所有内容都公开。

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.

相反,检查对象的作用以及作为该对象的某物意味着什么。然后创建为该对象提供自然接口的方法。自然接口涉及使用 getter 和 setter 公开一些内部属性,就这样吧。但重要的部分是您提前考虑并出于设计合理的原因创建了 getter/setter。

回答by AnT

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:


1.公共数据成员:

  • 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)
  • 提供对数据成员的读和写(如果不是 const)访问
  • 公开数据对象物理存在并且物理上是此类的成员这一事实(允许创建指向该数据成员的成员指针类型的指针)
  • 提供对数据成员的左值访问(允许创建指向成员的普通指针)


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


2. 返回对数据片段(可能是私有数据成员)的引用的方法:

  • provides both read and write (if not const) access to the data
  • exposes the fact that data object physically exists but does not exposethat 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):


3. getter 和/或 setter 方法(可能访问私有数据成员):

  • provides both read and/or write access to the property
  • does not exposethe 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 providelvalue 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.

getter/setter 方法甚至没有公开属性由物理对象实现的事实。即在 getter/setter 对后面可能没有物理数据成员。

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.

考虑到上述情况,看到有人声称 getter 和 setter 对与公共数据成员相同,这很奇怪。事实上,他们没有任何共同点。

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).

当然,每种方法都有其变体。例如,getter 方法可能会返回对数据的 const 引用,这会将其放置在 (2) 和 (3) 之间的某个位置。

回答by AnT

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.

如果您的每个数据项都有 getter 和 setter,那么将数据设为私有就没有意义了。这就是为什么为每个数据项设置 getter 和 setter 是个坏主意。考虑 std::string 类 - 它(可能)只有一个 getter、size() 函数,并且根本没有 setter。

Or consider a BankAccountobject - 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 ).

或者考虑一个BankAccount对象 - 我们应该使用 SetBalance()setter 来改变当前的平衡吗?不,大多数银行不会感谢你实施这样的事情。相反,我们想要类似ApplyTransaction( Transaction & tx ).

回答by Jerry Coffin

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.

公开数据。在(相当不可能的)事件中,您有一天需要“getter”或“setter”中的逻辑,您可以将数据类型更改为重载operator=和/或operator T(其中 T=您现在使用的任何类型)的代理类实现必要的逻辑。

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!) notcontrolling 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 reducesthe 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 realencapsulation -- except for one obscure corner case, it completely hidesthe fact that what is logically a piece of data is actually implemented via a pair of functions.

使用 getter 或 setter 实际上降低了抽象级别并公开了实现——它要求客户端代码意识到这个特定的类将逻辑上的“数据”实现为一对函数(getter 和 setter)。使用我上面建议的代理提供了真正的封装——除了一个模糊的极端情况,它完全隐藏了这样一个事实,即逻辑上的数据实际上是通过一对函数实现的。

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 operationsinstead 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.

当然,这需要放在上下文中:对于某些类,“数据”根本不是一个好的抽象。一般来说,如果您可以提供更高级别的操作而不是数据,那就更可取了。尽管如此,有些类最有用的抽象是读取和写入数据——在这种情况下,(抽象的)数据应该像任何其他数据一样可见。获取或设置值可能涉及的不仅仅是简单的位复制这一事实是一个应该对用户隐藏的实现细节。

回答by Justin Niessner

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).

Getter 和 Setter 使您可以将逻辑应用于来自私有成员的输入/输出,从而控制对数据的访问(对了解其 OO 术语的人进行封装)。

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.

但是请记住,这并不意味着每个私有变量都需要自己的 getter/setter。Neil 在他的银行示例中提出了一个很好的观点,即有时 Getter/Setter 没有意义。

回答by Igor Krivokon

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.

如果您非常确定您的逻辑很简单,并且在读/写变量时永远不需要做其他事情,那么最好将数据公开。在 C++ 的情况下,我更喜欢使用 struct 而不是 class 来强调数据是公开的这一事实。

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.

然而,在访问数据成员时,您经常需要做一些其他的事情,或者您想给自己以后添加此逻辑的自由。在这种情况下,getter 和 setter 是个好主意。您的更改对代码的客户端是透明的。

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

附加功能的一个简单示例 - 您可能希望每次访问变量时都记录调试字符串。

回答by BlueRaja - Danny Pflughoeft

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.

除了封装问题(这已经足够了),当您有 getter/setter 时,只要设置/访问变量,就很容易设置断点。

回答by Ian Goldby

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

使用公共字段而不是 getter 和 setter 的原因包括:

  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).
  1. 没有非法值。
  2. 客户应该编辑它。
  3. 能够写出诸如 object.XY = Z 之类的东西。
  4. 做出强有力的承诺,即价值只是一个价值,并且没有与之相关的副作用(将来也不会)。

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.)

(摘自关于基于价值的编程的十个问题。)

回答by John R. Strohm

On a strictly practical basis, I'd suggest you start by making all of your data members private, ANDmake 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.

在严格的实践基础,我建议你通过使所有数据成员的私人的启动,使他们的getter和setter私人。当您发现世界其他地方(即您的“(l) 用户社区”)实际需要什么时,您可以公开适当的 getter 和/或 setter,或者编写适当控制的公共访问器。

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.

此外(为了 Neil 的利益),在调试期间,当读取或写入特定数据成员时,有一个方便的地方挂起调试打印和其他操作有时很有用。使用 getter 和 setter,这很容易。对于公共数据成员来说,这是一个巨大的后路痛苦。

回答by Hitokage

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).

我相信仅使用 getter 和 setter 来获取和设置值是没有用的。使用这种方法的公共成员和私有成员之间没有区别。仅当您需要以某种方式控制值或认为将来可能有用时才使用 getter 和 setter(添加一些逻辑不会让您编辑其余代码)。

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

作为参考,请阅读 C++ 指南 (C.131)