tags:

views:

359

answers:

12

Asking this question because I feel that member variables of my base will be needed later in derived classes. Is there a drawback of making them protected?

EDIT: Edited to better show my intention.

EDIT: @sbi : Is this also wrong?

This class will be used for error recording and retrieving in other classes. Is it better to derive from it or use an object of it - I don't know. But I think the getter and setter methods are what this class is all about.

class ErrorLogger
{
   public:
      //Making this function virtual is optional
      virtual void SetError(const char*, ...);
      const char* GetError() const;
   protected:
      char* z_ErrorBuf;
};
+3  A: 

I am curious of what other people will answer to that.

As well as for the accessors paradigm, you may declare them private and use protected Getter and Setter methods. If your base class implementation changes, you only have those getter and setter to modify.

Benoit
+2  A: 

If you think child classes will need access to those variables later then yes, make them protected.

There is no drawback, as long as the aforementioned condition is met.

If you want to take the extra step and protect your variables from outside access, you could always create private member variables and then use protected methods to access/modify those private variables.

Justin Niessner
+1  A: 

Inheriting is just another way of using a class. It is more coupled and by making your member variables protected, you couple even more, so you shouldn't change them without knowing the impact on every inherited class. If it is your base-class and your inherited classes, there's probably not going to be any harm, but you do lose control of how members should be accessed (locking, logging, read/write, persistency,...).

stefaanv
A: 

Your overall class design will show you if you will end up with protected members or not. Whether you make them private, protected or public, that isn't something thats chiseled in the stone, so feel free to create your class tree without much thinking about that. If at first you don't know if the member will be used by derived class, and in what way, you'll surely find out when coding.

Most important thing to decide is what is public vs /private, because that's the way you present your class to the outside world.

Daniel Mošmondor
+16  A: 

Encapsulation is one of the main features of OO. Encapsulating your data in classes means that users of the class can not break the class' data's invariants, because the class' state can only be manipulated through its member functions.

If you allow derived classes access to their base class' data, then derived classes need to take care to not to invalidate the base class' data's invariants. That throws encapsulation out of the window and is just wrong. (So do getters and setters, BTW.)

I find myself using protected less and less over the years, even for member functions. If a class fully implements a simple concept, then all of its state should be manipulatable through its public interface. If derived classes need "back doors" to sneak in, then I usually question my design. (Which isn't to say I never use protected. I just find I need it less and less.)

sbi
And anyway you should always create variables as private and use protected Properties / accessors.
SoMoS
@SoMoS: Please look at the linked document regarding setters and getters. They are an abomination.
sbi
@SoMoS: I disagree 107%. An architecture that uses simple getters and setters to access a variable is silly. Just make the damned things public. What's the difference?
John Dibling
@John Dibling: Exposing the member variables by making them public makes the code more brittle. If you need to add some extra calculations on setting somewhere down the road, having the member exposed through a setter means that only the class that contains the member has to change, not all the classes that use that class. I guess you have to balance YAGNI with future proofing.
Robert Gowland
@Robert: Exposing the member variables via getters/setters makes the code 0.01% less brittle than exposing them publicly. What an achievement! Again, go and read the document I linked to. Conrad Weisert explains it so much better than I ever could.
sbi
John Dibling
An additional point: Adding 10 lines of code where zero would suffice also makes your code more brittle.
John Dibling
If member variables are public, that creates an obligation for all derived classes to use and maintain them. Protected variables create a contract which is only binding upon the base class. If classes "bar" and "boz" derive from "foo", an outsider who accepts a "foo" will have no way of knowing whether he's really going to get a "foo", a "bar", or a "boz", but any object of type "bar" can be 100% certain that its base object will be a "foo" and not a "boz".
supercat
@supercat: ITYM _"Private_ variables create a contract..."
sbi
@sbi: I use a shotgun on my fellow developers for any `protected` variable I come upon during code reviews. I do use `protected` methods though, especially the constructors / copy / assignment / destructor (avoiding virtuality issues), even though I am fully conscious that it's not much better than a simple comment anyway.
Matthieu M.
@Matthieu: Yes, protected constructors are a really helpful thing. BTW, how many of your fellow-developers are left? And where are they hiding when it's time for code review? `:)`
sbi
@sbi: I am afraid none are left, the most difficult having been to shoot myself of course :-) I must admit I'm lucky enough that they understand I am critizing *the code* in order to improve it (and them) and thus that they do not take it personally.
Matthieu M.
@Matthieu: Sounds like a good working environment!
sbi
I edited the question. Please refer to it for more trouble. :)
nakiya
@sbi: No, I meant "protected". Private variables don't create any contract with anyone. When I say "base class" I mean the class that actually declares the variables, as distinct from any classes derived therefrom.
supercat
@supercat: Then either I'm still misunderstanding you or the sentence "Protected variables create a contract which is only binding upon the base class." is wrong. The problem with protected data is that it binds derived classes to the contracts of the base class. Derived classes can mess with their base class' protected data, but must do so very carefully. In essence, derived classes need to know the innards of their base class.
sbi
@nakiya: As it stands, that class is just a needless wrapper around `z_ErrorBuf`. What can it do that a plain `const char*` cannot? (Don't get me wrong: I'm all against using `const char*` for anything but string literals. But your class doesn't improve on that.)
sbi
@sbi: Perhaps I'm confusing c++ meanings with other languages, but my understanding is that even if the parent of a class has a field, method, or property 'foo', the class can define its own 'foo' which will be seen by any derived classes. If the base-class 'foo' is public, then it can still be accessed by typecasting the derived-class object to the base class, but if it's protected, that won't work. Is my understanding in error?
supercat
@sbi: Try this for an explanation: if class 'foo' exposes a public field called 'count', and class 'bar' which derives from 'foo' doesn't use and maintain it as expected, then any class which accepts a 'foo' will malfunction if it is passed a 'bar' instead. There's no reason to expect that someone who uses a 'foo' will read the documentation for 'bar', especially since the code that uses 'foo' might be written before 'bar' even exists. If 'count' is 'protected' and a derived class documents that it doesn't use or maintain count, someone deriving from that class shouldn't be surprised.
supercat
@sbi: Perhaps your confusion is with the term "is binding upon". If a contract is only binding upon X, that means X promises to do something, but makes no claim about whether derived properties will do likewise. Derived properties would be the beneficiaries of the contract formed by protected members, but would not be obligated to extend such benefits to any further-derived classes.
supercat
@sbi: `SetError` may not be a simple function. It may do additional things ranging from appending a string to the beginning of the error to logging to outputting the errors. And, it will suppress code duplication if more than one class wants to expose `GetError` and `SetError` functions. Then, if one class needs to override the behavior of SetError, it can do so because it has access to `z_ErrorBuf`. Or am I thinking about it the wrong way?
nakiya
@nakiya: Well, then that might be an algorithm. Algorithms, however, are best implemented as _functions_, not as _objects_. Objects are best used to combine state (data) with behavior (member functions). If that is an _interface_ that might change my opinion, but I explicitly wrote "as it stands...".
sbi
@supercat: Yes, I think your understanding is in error. When you have a pointer or a reference to a base class object, naming any identifier of it will never refer to a derived class identifier of the same name - _except for virtual functions_. And that is completely orthogonal to member access levels. As for the binding to a contract: A base class' interfaces is like a contract made with the class' users. Derived classes are bound to this, too, since they can be treated as base class objects. If derived classes have access to the base class' data, it might inadvertently break such a contract.
sbi
@sbi: A derived class shouldn't mess with protected fields in a base class unless the author knows what he's doing and those aspects of the base class are immutable. From my understanding, though, a creator of a derived class has the ability to determine which protected members of the parent class will be available to further-derived classes. Thus, if the class behaves in a way that would render protected members meaningless, it can prevent any other classes from accessing them.
supercat
@supercat: My answer's point was that derived classes should __never__ mess with their base class' innards, because in order to "know what they are doing" they need a fully understanding of those innards. Basically, they need to fully know the implementation. But that's not encapsulation anymore. Oh, and short of not deriving publicly (and then it isn't a Is-A relationship anymore), a derived class can do nothing to prevent further derived classes from accessing its own base class.
sbi
Anyone who inherits from a class has a duty to know what the class is doing. Programmers who use a class, however, have no duty to know everything derived classes might do. It is true that someone who inherits a class could abuse protected members, but it's not the fault of the original class programmer if another programmer fails to do his duties. Making class data structures unavailable to derived classes will often limit the efficiency of those derived classes; hiding them behind non-virtual getters and setters will improve nothing, and using virtual ones invites disaster.
supercat
@supercat: "Anyone who inherits from a class has a duty to know what the class is doing." No. They just have to know the public and protected interface of the class. If you derive from a class, usually you do this to _extend its public interface_, or plug into its virtual function sockets, but not to rummage in its innards. Doing the latter abuses OO.
sbi
A: 

Protected data has all the drawbacks of public data, so you might as well make them public.

kotlinski
+1  A: 

If you make them private and later decide that they need to be accessible to derived classes, you can change them to be protected without affecting any code dependent on that class. You also have the option of adding protected accessors.

If you make them protected and later decided that should be private, changing them could break existing code that relies on them being available.

My personal rule of thumb is to make everything private and promote them up the visibility chain as necessary.

Ferruccio
+1  A: 

As long as you didn't intentionally design the class to be inherited from then there's no reliable way to guess what methods should be virtual and what members should be protected. The only thing you can be sure about is that you'll very likely guess wrong.

Don't mess around with this, use the sealed keyword and make the members private. You can always refactor later, you will have to anyway.

Hans Passant
Standard C++ has no `sealed` keyword.
Alf P. Steinbach
Oops, wrong tag. Well, same idea but minus *sealed*.
Hans Passant
@downvoter - don't blame me for the language missing the keyword.
Hans Passant
A: 

Provide a protected getter and maybe setter to the private internal variable, it's a little more code, but it's much cleaner.

Adam
A: 

You don't make members public for a reason. Even if those members can be freely set or got. You provide dummy public setters and getters. For EXACTLY THE SAME REASON you should NOT make members protected. Instead, you should provide protected setters and getters. The symmetry is very strong.

Armen Tsirunyan
I disagree. See the commentary in sbi's post
John Dibling
@John: I can even understand why you disagree. But my point here is "IF" it is bad to have public members, "THEN" is it bad to have protected members. But, indeed, the categorical ban for public members is debatable.
Armen Tsirunyan
@Armen: Ah, I see what you're saying now.
John Dibling
A: 

Making something 'public' creates a contract that will be binding upon all inherited classes. Making something 'protected' creates a contract with directly-inherited classes, but does not compel the classes to make such a contract available to any of their descendants.

If one expects that the source code for a base class will be available to anyone who is inheriting from it, and expects that the base class will never change (typically this means that the reason for using the base class is to allow public members and properties of the base-class to be used interchangeably with derived classes, rather than to reduce the amount of code needed for the derived classes) and if all public methods are virtual or tie directly into virtual methods, there's not much disadvantage to using protected fields rather than protected virtual getters/setters. If a descendant class needs to change the way the fields are used, it can simply override all the methods that use them.

If one expects that derived classes may be created in situations where the classes above them in the hierarchy are not completely known or are not immutable, then it may be more appropriate to have protected getters/setters, but that responsibility could be left with whoever creates the 'opaque' layers in the hierarchy.

Example: a collection might maintain a field called 'count'. A base version of the collection may store things in a way that makes it easy to maintain a field that always holds the number of items, but a derived version might store things in a way that makes it difficult. By having a field called "count", the base class promises its direct descendants that it will maintain the number of items in that field. A derived class might store things differently, such that a "count" field wasn't meaningful. Such a class could shadow the count field with a read-only property; its descendants would know that they had to read a property, while descendants of the original class would know that they could read a field.

The most important point is that protected things in a class only create a contract with direct descendants, and those descendants can decide whether or not to make a similar contract available to sub-descendants.

Addendum: the only thing gained by adding protected virtual getters and setters will be the ability for derived classes to change how the base class code accesses the fields/properties. Sometimes this will be necessary, but more often it will create problems. For example, if a collection may frequently have recently-added items deleted, a derived class may wrap things so that the last few items added are kept in a small "bonus" collection and transferred to the main collection after enough additional items are added. Code for the main collection will be expecting its own "count" field to indicate how many items are in the main collection. If a descendant class overrides the "count" property to include its own items, the main code will break. The descendant class should instead shadow the count field so its descendants will see a count that includes the bonus items, but the base class will still see the count which only includes its own items.

supercat
+1  A: 

Personnally, I usually try to restrict my use of protected to virtual things.

I consider any other use of protected as conceptually equivalent to public. In the sense that if you write a non virtual protected method, write it as if it was public. Same for a field. If the field would break something if it was public, it will also break something if it's protected.

It doesn't mean it's bad to have a protected field or non virtual method, it just means you have to be careful and deliberate with their use, and know that someone, somewhere, can use those things and potentially break your class simply by deriving it.

Coincoin
@Coincoin: IMHO, protected virtual is sometimes appropriate, but shadowing is often more appropriate than overriding. See the addendum to my answer.
supercat