公共数据成员与 Getters、Setters

发布于 2024-09-04 03:13:17 字数 366 浏览 6 评论 0原文

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

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

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

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.

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.

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(15

审判长 2024-09-11 03:13:17

两者都不。你应该有做事的方法。如果其中一件事情恰好与特定的内部变量相对应,那就太好了,但不应该有任何东西可以将这一点传达给类的用户。

私有数据是私有的,因此您可以随时替换实现(并且可以进行完全重建,但这是一个不同的问题)。一旦你把精灵从瓶子里拿出来,你会发现不可能把它推回去。

编辑:根据我对另一个答案的评论。

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

就个人而言,getter/setter 是两害相权取其轻。因为一旦开始制作 getter/setter,人们就不再以挑剔的眼光来设计对象,哪些数据应该可见,哪些数据不应该可见。对于公众成员来说情况更糟,因为倾向于将一切都公开。

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

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.

恋竹姑娘 2024-09-11 03:13:17

不,这根本不是同一件事。

可以通过类接口的不同方法来实现不同级别的保护/实现隐藏:

1. 公共数据成员:

  • 提供对数据成员的读和写(如果不是 const)访问,
  • 暴露了数据对象物理存在并且物理上是此类的成员这一事实(允许创建指向成员类型的指针到该数据成员)
  • 提供对数据成员的左值访问(允许创建指向该成员的普通指针)

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

  • 提供对数据的读和写(如果不是 const)访问,
  • 暴露了数据对象物理存在但不存在的事实公开它实际上是此类的成员(不允许创建指向数据的成员指针类型的指针)
  • 提供对数据的左值访问(允许创建指向它的普通指针)

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

  • 提供对属性的读和/或写访问
  • 不暴露数据对象物理存在的事实,更不用说物理存在在此类中(不允许创建指向该数据的成员指针类型的指针,或任何类型的指针)
  • 不提供对数据的左值访问(不允许一个创建指向它的普通指针)

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

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

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

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

百思不得你姐 2024-09-11 03:13:17

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

或者考虑一个 BankAccount 对象 - 我们是否应该使用 SetBalance() setter 来更改当前余额?不,大多数银行不会感谢你实施这样的事情。相反,我们想要像 ApplyTransaction( Transaction & tx ) 这样的东西。

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

沉溺在你眼里的海 2024-09-11 03:13:17

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

编辑:控制对数据的访问构成封装的想法基本上是错误的。封装是关于隐藏实现的细节(一般来说!)控制对数据的访问。

封装是对抽象的补充:抽象处理对象的外部可见行为,而封装则处理隐藏该行为如何实现的细节。

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

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

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.

來不及說愛妳 2024-09-11 03:13:17

Getters 和 Setters 允许您将逻辑应用于私有成员的输入/输出,从而控制对数据的访问(对那些了解 OO 术语的人进行封装)。

公共变量使类的数据向公众开放,以进行不受控制和未经验证的操作,这几乎总是不可取的。

你也必须长期考虑这些事情。您现在可能没有验证(这就是为什么公共变量似乎是一个好主意),但它们有可能会在以后添加。提前添加它们会留下框架,因此减少了重构,更不用说验证不会以这种方式破坏依赖代码)。

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

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.

北陌 2024-09-11 03:13:17

如果您非常确定您的逻辑很简单,并且在读取/写入变量时不需要执行其他操作,那么最好将数据保持公开。在 C++ 情况下,我更喜欢使用结构而不是类来强调数据是公共的这一事实。

但是,在访问数据成员时,您经常需要执行一些其他操作,或者您希望稍后可以自由地添加此逻辑。在这种情况下,getter 和 setter 是个好主意。您的更改对于代码的客户端来说是透明的。

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

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.

卸妝后依然美 2024-09-11 03:13:17

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

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.

初吻给了烟 2024-09-11 03:13:17

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

  1. 不存在非法值。
  2. 预计客户将对其进行编辑。
  3. 能够编写诸如 object.XY = Z 之类的内容。
  4. 做出强有力的承诺,该值只是一个值,并且没有与之相关的副作用(并且将来也不会出现)。

根据您使用的软件类型,这些可能都是非常特殊的情况(如果您认为自己遇到过这种情况,那么您可能是错的)或者它们可能一直发生。这确实取决于。

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

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

愁以何悠 2024-09-11 03:13:17

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

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

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.

栩栩如生 2024-09-11 03:13:17

我一直认为,在大多数编程语言中,getter 和 setter 都是故意冗长的,特别是为了让你在使用它们时三思而后行 - 为什么你的调用者需要了解你的类的内部工作原理应该是你首先想到的问题。

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.

情魔剑神 2024-09-11 03:13:17

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

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

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)

╰ゝ天使的微笑 2024-09-11 03:13:17

我建议您不要拥有公共数据成员(POD 结构除外)。我也不建议您为所有数据成员设置 getter 和 setter。相反,为您的类定义一个干净的公共接口。这可能包括获取和/或设置属性值的方法,并且这些属性可以被实现为成员变量。但不要为所有成员创建 getter 和 setter。

这个想法是将接口与实现分开,允许您修改实现,而无需类的用户更改其代码。如果您通过 getter 和 setter 公开所有内容,那么与使用公共数据相比,您并没有任何改进。

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.

像极了他 2024-09-11 03:13:17

使用 getter 和 setter 将允许您修改向用户提供值的方式。

请考虑以下事项:

double premium;
double tax;

然后,您使用此溢价值在各处编写代码以获得溢价:

double myPremium = class.premium;

您的规格刚刚更改,从用户的角度来看,溢价需要是溢价+税

您必须修改代码中使用该 premium 值的所有位置,并向其中添加 tax

相反,如果您这样实现它:

double premium;
double tax;

double GetPremium(){return premium;};

您的所有代码都将使用 GetPremium() 并且您的 tax 更改将是一行:

double premium;
double tax;

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

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;};
戏舞 2024-09-11 03:13:17

返回值也会影响 getter 和 setter 的使用。获取变量的值或访问私有数据成员变量是有区别的。按值保持完整性,按引用或按指针则不然。

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.

唠甜嗑 2024-09-11 03:13:17

Getter 和 Setter 的存在主要是为了我们可以控制如何获取成员以及如何设置成员。 getter 和 setter 不仅仅作为访问特定成员的方式而存在,而是为了确保在我们尝试设置成员之前,它可能满足某些条件,或者如果我们获取它,我们可以控制返回该成员的副本成员(在非原始类型的情况下)。总的来说,当您想要通过管道方式与数据成员交互时,您应该尝试使用 g/s'ers,否则会导致以临时方式使用该成员。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文