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

发布于 2024-07-04 04:20:39 字数 40 浏览 13 评论 0原文

你应该使用受保护的成员变量吗? 这有什么优点以及会导致什么问题?

Should you ever use protected member variables? What are the the advantages and what issues can this cause?

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

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

发布评论

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

评论(10

美人迟暮 2024-07-11 04:20:46

有关 .Net 访问修饰符的详细信息 转到这里

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

For detailed info on .Net access modifiers go here

There are no real advantages or disadvantages to protected member variables, it's a question of what you need in your specific situation. In general it is accepted practice to declare member variables as private and enable outside access through properties. Also, some tools (e.g. some O/R mappers) expect object data to be represented by properties and do not recognize public or protected member variables. But if you know that you want your subclasses (and ONLY your subclasses) to access a certain variable there is no reason not to declare it as protected.

余厌 2024-07-11 04:20:45

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

受保护的成员变量具有显着的缺点,因为它们实际上允许客户端代码(子类)访问基类的内部状态。 这会阻止基类有效地维护其不变量。

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

访问器/修改器方法在维护过程中提供了更高的 API 稳定性和实现灵活性。

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

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

At the design level it might be appropriate to use a protected property, but for implementation I see no advantage in mapping this to a protected member variable rather than accessor/mutator methods.

Protected member variables have significant disadvantages because they effectively allow client code (the sub-class) access to the internal state of the base class class. This prevents the base class from effectively maintaining its invariants.

For the same reason, protected member variables also make writing safe multi-threaded code significantly more difficult unless guaranteed constant or confined to a single thread.

Accessor/mutator methods offer considerably more API stability and implementation flexibility under maintenance.

Also, if you're an OO purist, objects collaborate/communicate by sending messages, not reading/setting state.

In return they offer very few advantages. I wouldn't necessarily remove them from somebody else's code, but I don't use them myself.

总攻大人 2024-07-11 04:20:45

简而言之,是的。

受保护的成员变量允许从任何子类以及同一包中的任何类访问该变量。 这非常有用,特别是对于只读数据。 然而,我不认为它们是必要的,因为对受保护成员变量的任何使用都可以使用私有成员变量和几个 getter 和 setter 进行复制。

In short, yes.

Protected member variables allow access to the variable from any sub-classes as well as any classes in the same package. This can be highly useful, especially for read-only data. I don't believe that they are ever necessary however, because any use of a protected member variable can be replicated using a private member variable and a couple of getters and setters.

迷你仙 2024-07-11 04:20:45

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

Just for the record, under Item 24 of "Exceptional C++", in one of the footnotes, Sutter goes
"you would never write a class that has a public or protected member variable. right? (Regardless of the poor example set by some libraries.)"

债姬 2024-07-11 04:20:45

大多数时候,使用 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 会很痛苦,应该被禁止。

摘要 因此,您已经保护了派生类使用的数据。 尽管如此,我们必须考虑到基类应该是抽象的这一事实。

Most of the time, it is dangerous to use protected because you break somewhat the encapsulation of your class, which could well be broken down by a poorly designed derived class.

But I have one good example: Let's say you can some kind of generic container. It has an internal implementation, and internal accessors. But you need to offer at least 3 public access to its data: map, hash_map, vector-like. Then you have something 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. */ }

I used this kind of code less than a month ago (so the code is from memory). After some thinking, I believe that while the generic Base container should be an abstract class, even if it can live quite well, because using directly Base would be such a pain it should be forbidden.

Summary Thus, you have protected data used by the derived class. Still, we must take int o account the fact the Base class should be abstract.

一绘本一梦想 2024-07-11 04:20:44

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

以下是您的超类在将成员变量设置为受保护而不是带有访问器的私有变量后无法执行的操作:

  1. 在读取属性时动态创建一个值。 如果添加受保护的 getter 方法,则可以延迟创建值并将其传回。

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

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

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

一般来说,我认为在极少数情况下我会建议创建受保护的成员变量。 您最好花几分钟通过 getter/setter 公开属性,而不是在几个小时后跟踪修改受保护变量的其他代码中的错误。 不仅如此,您还可以确保在不破坏依赖代码的情况下添加未来的功能(例如延迟加载)。 以后做比现在做更难。

In general, I would keep your protected member variables to the rare case where you have total control over the code that uses them as well. If you are creating a public API, I'd say never. Below, we'll refer to the member variable as a "property" of the object.

Here's what your superclass cannot do after making a member variable protected rather than private-with-accessors:

  1. lazily create a value on the fly when the property is being read. If you add a protected getter method, you can lazily create the value and pass it back.

  2. know when the property been modified or deleted. This can introduce bugs when the superclass makes assumptions about the state of that variable. Making a protected setter method for the variable keeps that control.

  3. Set a breakpoint or add debug output when the variable is read or written to.

  4. Rename that member variable without searching through all the code that might use it.

In general, I think it'd be the rare case that I'd recommend making a protected member variable. You are better off spending a few minutes exposing the property through getters/setters than hours later tracking down a bug in some other code that modified the protected variable. Not only that, but you are insured against adding future functionality (such as lazy loading) without breaking dependent code. It's harder to do it later than to do it now.

时光倒影 2024-07-11 04:20:43

对我来说,关键问题是,一旦将变量设置为受保护,就不能允许类中的任何方法依赖其值在某个范围内,因为子类总是可以将其置于范围之外。

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

至关重要的是,从代码作为库发布的那一刻起,我永远无法做出这些假设,因为即使我更新设置器以保持纵横比,我也无法保证变量已被设置通过 setter 或通过现有代码中的 getter 访问。

我的类的任何子类也不能选择做出这种保证,因为它们也不能强制执行变量值,即使这是其子类的全部要点

举个例子:

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

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

The key issue for me is that once you make a variable protected, you then cannot allow any method in your class to rely on its value being within a range, because a subclass can always place it out of range.

For example, if I have a class that defines width and height of a renderable object, and I make those variables protected, I then can make no assumptions over (for example), aspect ratio.

Critically, I can never make those assumptions at any point from the moment that code's released as a library, since even if I update my setters to maintain aspect ratio, I have no guarantee that the variables are being set via the setters or accessed via the getters in existing code.

Nor can any subclass of my class choose to make that guarantee, as they can't enforce the variables values either, even if that's the entire point of their subclass.

As an example:

  • I have a rectangle class with width and height being stored as protected variables.
  • An obvious sub-class (within my context) is a "DisplayedRectangle" class, where the only difference is that I restrict the widths and heights to valid values for a graphical display.
  • But that's impossible now, since my DisplayedRectangle class cannot truly constrain those values, as any subclass of it could override the values directly, while still being treated as a DisplayedRectangle.

By constraining the variables to be private, I can then enforce the behaviour I want through setters or getters.

鸠魁 2024-07-11 04:20:42

现在的普遍感觉是它们导致派生类与其基类之间的过度耦合。

与受保护的方法/属性相比,它们没有特别的优势(从前它们可能具有轻微的性能优势),并且它们在深度继承盛行的时代也被更多地使用,但目前还没有。

The general feeling nowadays is that they cause undue coupling between derived classes and their bases.

They have no particular advantage over protected methods/properties (once upon a time they might have a slight performance advantage), and they were also used more in an era when very deep inheritance was in fashion, which it isn't at the moment.

兮子 2024-07-11 04:20:41

一般来说,如果某件事不是故意被认为是公开的,我就会将其设为私有。

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

这种情况几乎不会发生——我真的一点也不喜欢继承,因为它不是模拟大多数情况的特别好的方法。 无论如何,继续吧,不用担心。

我想说这对于大多数开发人员来说很好(而且可能是最好的方法)。

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

唯一真正的例外是,如果您从事以黑盒形式向第三方传送二进制 DLL 的业务。 这基本上由 Microsoft、那些“自定义 DataGrid 控件”供应商组成,可能还包括其他一些附带可扩展性库的大型应用程序。 除非您属于这一类,否则不值得花费时间/精力来担心这类事情。

Generally, if something is not deliberately conceived as public, I make it private.

If a situation arises where I need access to that private variable or method from a derived class, I change it from private to protected.

This hardly ever happens - I'm really not a fan at all of inheritance, as it isn't a particularly good way to model most situations. At any rate, carry on, no worries.

I'd say this is fine (and probably the best way to go about it) for the majority of developers.

The simple fact of the matter is, if some other developer comes along a year later and decides they need access to your private member variable, they are simply going to edit the code, change it to protected, and carry on with their business.

The only real exceptions to this are if you're in the business of shipping binary dll's in black-box form to third parties. This consists basically of Microsoft, those 'Custom DataGrid Control' vendors, and maybe a few other large apps that ship with extensibility libraries. Unless you're in that category, it's not worth expending the time/effort to worry about this kind of thing.

臻嫒无言 2024-07-11 04:20:40

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

取决于您对隐藏状态的挑剔程度。

  • 如果您不想泄漏任何内部状态,那么将所有成员变量声明为私有是可行的方法。
  • 如果您并不真正关心子类可以访问内部状态,那么 protected 就足够了。

如果开发人员出现并对您的类进行子类化,他们可能会搞砸,因为他们不完全理解它。 对于私有成员,除了公共接口之外,他们无法看到事情如何完成的具体实现细节,这使您可以在以后灵活地更改它。

Should you ever use protected member variables?

Depends on how picky you are about hiding state.

  • If you don't want any leaking of internal state, then declaring all your member variables private is the way to go.
  • If you don't really care that subclasses can access internal state, then protected is good enough.

If a developer comes along and subclasses your class they may mess it up because they don't understand it fully. With private members, other than the public interface, they can't see the implementation specific details of how things are being done which gives you the flexibility of changing it later.

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