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

你应该使用受保护的成员variables吗? 有什么优势,这可能导致什么问题?

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

取决于你是如何挑剔隐藏国家。

  • 如果你不想泄漏任何内部状态,那么声明你所有的成员variables是私密的。
  • 如果你真的不在乎那个子类可以访问内部状态,那么protected就足够好了。

如果一个开发者出现并将你的课程分类,他们可能会搞砸了,因为他们完全不了解它。 除了公共接口以外的私有成员,他们不能看到具体实现的具体细节如何实现,从而使您可以稍后改变它。

现在的一般感觉是它们导致派生类和它们的基础之间的不适当的耦合。

它们在保护方法/属性方面没有特别的优势(曾几何时它们可能会有轻微的性能优势),在非常深刻的inheritance时尚的时代,它们也被用得更多。

一般来说,如果有些东西不是故意构想成公共的,我就把它变成私人的。

如果出现需要从派生类访问该私有variables或方法的情况,则将其从私有变为受保护。

这几乎没有发生 – 我真的不是一个inheritance的粉丝,因为它不是模型大多数情况下一个特别好的方法。 无论如何,不​​要担心。

我想说这对大多数开发人员来说是好的(也许是最好的方法)。

事情的一个简单的事实是 ,如果其他开发人员在一年后出现并决定需要访问您的私有成员variables,那么他们只需编辑代码,将其更改为受保护,并继续进行业务。

唯一真正的例外是如果您将二进制DLL以黑匣子forms发送给第三方的业务。 这基本上由微软,那些“自定义DataGrid控件”供应商,也许还有一些其他大型应用程序带有可扩展性库。 除非你属于这个类别,否则不值得花时间/精力来担心这种事情。

一般来说,我会保留你的受保护的成员variables,在极less数情况下,你也可以完全控制使用它们的代码。 如果你正在创build一个公共API,我会说永远不会。 下面,我们将引用成员variables作为对象的“属性”。

这是你的超类在保护成员variables而不是private-with-accessors后不能做的事情:

  1. 懒惰地创造一个财产正在读取时的价值。 如果添加受保护的getter方法,则可以懒惰地创build该值并将其传回。

  2. 知道财产何时被修改或删除。 当超类对这个variables的状态做出假设时,这会引入错误。 为这个variables创build一个受保护的setter方法来保持这个控制。

  3. 设置断点或在读取或写入variables时添加debugging输出。

  4. 重命名该成员variables而不search所有可能使用它的代码。

一般来说,我认为这是罕见的情况下,我build议做一个受保护的成员variables。 你最好花几分钟时间通过getters / setter来暴露这个属性,而不是几个小时之后追踪修改受保护variables的其他代码中的一个bug。 不仅如此,而且您还可以确保在不破坏相关代码的情况下添加未来的function(如延迟加载)。 晚点做比现在做得更难。

在devise层面上,使用受保护的属性可能是适当的,但是对于实现,我们认为将其映射到受保护的成员variables而不是访问器/修改器方法没有什么优势。

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

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

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

另外,如果您是面向对象的纯粹主义者,对象通过发送消息进行协作/通信,而不是读取/设置状态。

作为回报,他们提供了很less的优势。 我不一定把他们从别人的代码中删除,但是我自己并没有使用它们。

对我来说关键的问题是,一旦你使一个variables保护,你不能允许你的类中的任何方法依赖于它的值在一个范围内,因为一个子类总是可以把它放在范围之外。

例如,如果我有一个定义可渲染对象的宽度和高度的类,并且使这些variables受保护,那么我就不会对(例如)纵横比做任何假设。

关键的是,从代码作为库发布的那一刻起,我永远无法做出这些假设,因为即使我更新了setter以保持纵横比,我也不能保证variables是通过setter设置的,获得者在现有的代码。

我们class的任何一个小class也不能select做出这样的保证,因为他们也不能执行variables值, 即使这是他们的子类的整个点

举个例子:

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

通过将variables约束为私有的,我可以通过setter或getter来强制执行我想要的行为。

大多数时候,使用保护是危险的,因为你稍微打破了你的类的封装,很可能被devise得很差的派生类分解。

但是我有一个很好的例子:假设你可以使用某种通用容器。 它有一个内部实现和内部访问器。 但是您至less需要提供3个公共访问其数据:map,hash_map,vector-like。 那么你有这样的东西:

 template <typename T, typename TContainer> class Base { // etc. protected TContainer container ; } template <typename Key, typename T> class DerivedMap : public Base<T, std::map<Key, T> > { /* etc. */ } template <typename Key, typename T> class DerivedHashMap : public Base<T, std::hash_map<Key, T> > { /* etc. */ } template <typename T> class DerivedVector : public Base<T, std::vector<T> > { /* etc. */ } 

我不到一个月前使用这种代码(所以代码是从内存中)。 经过一番思考,我认为虽然通用Base容器应该是一个抽象类,即使它可以生活得很好,因为直接使用Base将是一个很难被禁止的东西。

总结因此,您已经保护派生类使用的数据。 尽pipe如此,我们必须考虑基类应该是抽象的事实。

总之,是的。

受保护的成员variables允许从任何子类访问variables以及同一个包中的任何类。 这可能非常有用,特别是对于只读数据。 但是我不相信它们是必须的,因为任何使用受保护的成员variables都可以使用私有成员variables和一些getter和setter来复制。

有关.Net访问修饰符的详细信息, 请转到此处

受保护的成员variables没有真正的优点或缺点,这是您在特定情况下需要的问题。 一般来说,将成员variables声明为私有的并通过属性启用外部访问是公认的做法。 此外,一些工具(例如一些O / R映射器)期望对象数据由属性表示,并且不识别公共或受保护的成员variables。 但是如果你知道你希望你的子类(只有你的子类)访问某个variables,没有理由不把它声明为受保护的。

在“Exceptional C ++”第24条的脚注中,Sutter写道:“你永远不会写一个具有公共或受保护成员variables的类,对吗?(不pipe某些库设置的不好的例子。)”