oop - variable - when to use protected vs private

Should you ever use protected member variables? (7)

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.

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

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.

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.

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.

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

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

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.