你应该使用受保护的成员变量吗?

Joh*_*ing 94 oop protected

你应该使用受保护的成员变量吗?有什么优势,这会带来什么问题?

All*_*nde 71

你应该使用受保护的成员变量吗?

取决于你对隐藏状态的挑剔程度.

  • 如果您不希望任何内部状态泄漏,那么将所有成员变量声明为私有是最佳选择.
  • 如果你真的不在乎子类可以访问内部状态,那么受保护就足够了.

如果开发人员出现并将您的类子类化,他们可能会搞砸,因为他们不完全理解它.对于除公共界面之外的私有成员,他们无法看到实现方式的实现具体细节,这使您可以灵活地在以后更改它.

  • @Jake:您永远不应该根据性能假设做出设计决策.您根据您认为最佳设计做出设计决策,并且只有当您的现实生活分析显示您的设计瓶颈时,您才能去修复它.通常如果设计合理,性能也很好. (20认同)
  • 我要说这不值得担心,除非你通过剖析发现瓶颈最终成为存取者(它几乎从来没有).如果最终成为一个问题,可以采取一些技巧使JIT变得更聪明.例如,在java中,您可以通过将其标记为final来暗示访问者可以内联.诚实地说,getter和setter的性能远不如处理系统组织和由分析器确定的实际性能问题重要. (3认同)
  • @Black显然Allain意味着"他们不能**访问**"这些成员因此无法构建针对他们的代码,让该类作者可以在以后随意删除/更改受保护的成员.(当然,pimpl习语可以直观地隐藏它们,也可以从包括标题在内的翻译单元中隐藏它们.) (2认同)

Wil*_*ean 30

现在普遍的感觉是它们导致派生类和它们的基础之间的过度耦合.

它们与受保护的方法/属性相比没有特别的优势(曾几何时它们可能具有轻微的性能优势),并且它们也被用于更深层次的继承时尚的时代,而现在还没有.

  • More remarkable still is that I actually agree with myself across that amount of time... (9认同)
  • 不应该"对受保护的方法/属性没有特别的优势"对*private*methods/properties`没有特别的优势吗? (2认同)

Ori*_*rds 29

一般来说,如果某些东西不是故意设想为公开的,我会把它私有化.

如果出现需要从派生类访问该私有变量或方法的情况,我将其从private更改为protected.

这几乎不会发生 - 我真的不是所有继承的粉丝,因为它不是模拟大多数情况的特别好的方法.无论如何,继续,不用担心.

对于大多数开发人员来说,我说这很好(也许是最好的方法).

问题的简单事实是,如果其他开发人员一年后出现并决定他们需要访问您的私有成员变量,他们只需编辑代码,将其更改为受保护,并继续他们的业务.

唯一真正的例外情况是,如果您的业务是以黑盒形式将二进制dll发送给第三方.这基本上包括Microsoft,那些"Custom DataGrid Control"供应商,以及可能带有可扩展性库的其他一些大型应用程序.除非你属于那个类别,否则不值得花时间/精力去担心这类事情.


Mic*_*hop 7

一般情况下,我会将受保护的成员变量保留在极少数情况下,您可以完全控制使用它们的代码.如果您正在创建公共API,我会说永远不会.下面,我们将成员变量称为对象的"属性".

这是你的超类在使成员变量受保护而不是私有访问者后不能做的事情:

  1. 在阅读该属性时,懒惰地创建一个值.如果添加受保护的getter方法,则可以懒惰地创建值并将其传回.

  2. 知道何时修改或删除了该属性.当超类对该变量的状态做出假设时,这可能会引入错误.为变量创建受保护的setter方法可以保持该控制.

  3. 在读取或写入变量时设置断点或添加调试输出.

  4. 重命名该成员变量,而不搜索可能使用它的所有代码.

一般来说,我认为我建议制作受保护的成员变量是极少数情况.最好花几分钟时间通过getter/setter暴露财产,而不是几小时后追踪修改受保护变量的其他代码中的错误.不仅如此,您还可以避免在不破坏相关代码的情况下添加未来的功能(例如延迟加载).现在做这件事要比现在做得更难.


ric*_*chj 7

在设计级别,使用受保护的属性可能是合适的,但是对于实现,我认为将其映射到受保护的成员变量而不是accessor/mutator方法没有任何优势.

受保护的成员变量具有明显的缺点,因为它们有效地允许客户端代码(子类)访问基类类的内部状态.这可以防止基类有效地维护其不变量.

出于同样的原因,受保护的成员变量也使编写安全的多线程代码变得更加困难,除非保证不变或局限于单个线程.

Accessor/mutator方法在维护时提供了更多的API稳定性和实现灵活性.

此外,如果您是OO纯粹主义者,则对象通过发送消息进行协作/通信,而不是读取/设置状态.

作为回报,它们提供的优势很少.我不一定会从其他人的代码中删除它们,但我不会自己使用它们.


dew*_*rde 6

对我来说,关键问题是,一旦你对变量进行了保护,你就不能允许你的类中的任何方法依赖于它在一个范围内的值,因为子类总是可以将它放在范围之外.

例如,如果我有一个定义可渲染对象的宽度和高度的类,并且我使这些变量受到保护,那么我就不能对(例如)宽高比做出任何假设.

至关重要的是,从代码作为库发布的那一刻起,我就永远无法做出这些假设,因为即使我更新我的setter以保持宽高比,我也无法保证变量是通过setter设置的,也可以通过现有代码中的getter.

我的类的任何子类也不能选择保证,因为它们也不能强制执行变量值,即使这是它们子类的整个点.

举个例子:

  • 我有一个宽度和高度的矩形类存储为受保护的变量.
  • 一个明显的子类(在我的上下文中)是一个"DisplayedRectangle"类,唯一的区别是我将宽度和高度限制为图形显示的有效值.
  • 但现在这是不可能的,因为我的DisplayedRectangle类不能真正约束这些值,因为它的任何子类都可以直接覆盖这些值,同时仍被视为DisplayedRectangle.

通过将变量约束为私有,我可以通过setter或getter强制执行我想要的行为.


hAc*_*oCk 5

仅供记录,在“Exceptional C++”第 24 项下的一个脚注中,Sutter 说道“你永远不会编写一个具有公共或受保护成员变量的类。对吗?(不管某些库设置的糟糕示例如何) .)”