Answers:
您是否应该使用受保护的成员变量?
取决于您对隐藏状态的挑剔程度。
如果开发人员出现并为您的类提供子类,则他们可能会弄乱它,因为他们无法完全理解。对于私有成员(除了公共接口),他们看不到具体的实现细节,这使您以后可以灵活地进行更改。
如今的普遍感觉是,它们在派生类和它们的基础之间引起了不适当的耦合。
与受保护的方法/属性相比,它们没有什么特别的优势(一次过,它们可能会有一点性能上的优势),并且它们还被用在一个非常深入的继承成为时尚的时代,而现在还不是。
no particular advantage over protected methods/properties
应该no particular advantage over *private* methods/properties
吗?
super
构造来调用父构造器;然后它将负责在父类中初始化私有状态变量。
通常,如果不是故意将某些内容视为公开的,则将其设为私有。
如果出现需要从派生类访问该私有变量或方法的情况,请将其从私有更改为受保护。
这种情况几乎从未发生过-我真的不喜欢继承,因为它不是建模大多数情况的特别好方法。无论如何,继续前进,无后顾之忧。
我想这对大多数开发人员来说都是很好的(也许是最好的方法)。
问题的简单事实是,如果其他开发人员在一年后才出现并决定需要访问您的私有成员变量,他们将只是编辑代码,将其更改为受保护的代码并继续开展业务。
唯一真正的例外是,如果您要以黑盒形式将二进制dll运送给第三方。它主要由Microsoft,那些“自定义DataGrid控件”供应商以及可能带有扩展库的其他一些大型应用组成。除非您属于该类别,否则不值得花费时间/精力来担心这种事情。
对我而言,关键问题是,一旦将变量设置为受保护的变量,就不能再允许类中的任何方法依赖其值在范围内,因为子类始终可以将其置于范围之外。
例如,如果我有一个定义可渲染对象的宽度和高度的类,并且将那些变量设置为受保护的,那么我就不能对(例如)宽高比进行任何假设。
至关重要的是,从代码作为库发布之时起,我就无法在任何时候做出这些假设,因为即使我更新了设置器以保持宽高比,我也无法保证变量是通过设置器设置的,还是可以通过现有代码中的获取器。
我班的任何子类也不能选择做出保证,因为它们也不能强制执行变量值,即使那是其子类的全部要点。
举个例子:
通过将变量约束为私有,我可以通过设置器或获取器强制执行我想要的行为。
通常,在极少数情况下,即使您完全控制使用它们的代码,我也会保留受保护的成员变量。如果您要创建公共API,那我就说永远不要。下面,我们将成员变量称为对象的“属性”。
在将成员变量设置为受保护成员而不是带有访问者的私有变量之后,您的超类无法执行以下操作:
读取属性时,会懒惰地动态创建一个值。如果添加受保护的getter方法,则可以延迟创建值并将其传递回。
知道何时修改或删除属性。当超类对变量的状态进行假设时,这可能会引入错误。为该变量创建一个受保护的setter方法可以保留该控件。
读取或写入变量时设置断点或添加调试输出。
重命名该成员变量,而不搜索可能使用它的所有代码。
总的来说,我认为这是极少数情况,建议您创建一个受保护的成员变量。您最好花几分钟的时间通过getter / setter公开属性,而不是花几个小时在修改保护变量的其他代码中查找错误。不仅如此,还可以确保您在不破坏相关代码的情况下添加将来的功能(例如延迟加载)。迟做比现在做起来难。
在设计级别上,使用受保护的属性可能是适当的,但是对于实现而言,将其映射到受保护的成员变量而不是访问器/更改器方法没有好处。
受保护的成员变量具有明显的缺点,因为它们有效地允许客户端代码(子类)访问基类的内部状态。这阻止了基类有效地保持其不变性。
出于同样的原因,受保护的成员变量也使编写安全的多线程代码变得更加困难,除非保证常量或将其限制在单个线程中。
访问器/更改器方法在维护下可提供更大的API稳定性和实现灵活性。
另外,如果您是OO纯粹主义者,则对象通过发送消息(而不是读取/设置状态)进行协作/通信。
作为回报,它们几乎没有优势。我不一定要将它们从其他人的代码中删除,但我自己不会使用它们。
在大多数情况下,使用protected是很危险的,因为您会在某种程度上破坏类的封装,而这种封装很可能会被设计不良的派生类破坏。
但我有一个很好的例子:假设您可以使用某种通用容器。它具有内部实现和内部访问器。但是您至少需要提供对其数据的3种公共访问权限:map,hash_map,类似矢量。然后,您将得到以下内容:
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会很痛苦,因此应禁止使用。
总结因此,您已保护派生类使用的数据。尽管如此,我们必须考虑到基类应该是抽象的事实。
protected
不比封装public
。我愿意被证明是错误的。您要做的就是编写一个受保护成员的类,并禁止我对其进行修改。显然,该类必须是非最终的,因为使用protected的全部目的都是为了继承。某些东西被封装了,或者没有。没有中间状态。
有关.Net访问修饰符的详细信息,请单击此处
受保护的成员变量没有实际的优点或缺点,这是您在特定情况下需要什么的问题。通常,将成员变量声明为私有变量并允许通过属性进行外部访问是公认的惯例。同样,某些工具(例如某些O / R映射器)期望对象数据由属性表示,并且无法识别公共或受保护的成员变量。但是,如果您知道希望子类(并且仅子类)访问某个变量,则没有理由不将其声明为受保护的变量。