Reputation: 882
I have a base class and several derived classes. The derived classes use some common data, can I just put those common data as protected member of the base class? I know the protected member breaks encapsulation sometimes, so I wonder if there is any good approach.
Here is a specific example:
class Base{
public:
virtual void foo() = 0;
void printData();
protected:
std::vector<std::string> mData;
}
class Dr1 : public Base{
public:
virtual void foo(); //could change mData
}
class Dr2 : public Base{
public:
virtual void foo(); //could change mData
}
If I put mData into Dr1 and Dr2 as private member, then I need to put it in both of them, and I can not have printData() in Base since printData() need access to mData unless I make printData() virtual and have identical function in both Dr1 and Dr2, which doesn't make much sense to me.
Is there a better way to approach this without using protected member? Thank you.
Upvotes: 6
Views: 1508
Reputation: 32399
I've come to the conclusion that protected data is just as bad as public data in a class. If you ever need to change the protected data, you are going to break all the classes that derived from the base. Those derived classes are clients of your base class, just like the regular "public" users. I suggest writing protected accessor functions that derived classes can call. This gives you all the benefits of public member functions: you can change your implementation without breaking clients, and you can easily add instrumentation and error checking if needed.
Upvotes: 1
Reputation: 490338
This is open to considerable argument. Allowing data to be protected
was added to C++ largely because Mark Linton wanted it for the Interviews Windowing library he was designing. It seemed to fit reasonably well with the rest of the design of C++, so (apparently) Bjarne went along with the idea. After a few years, Mark had banned all use of protected data members in Interviews because of the number of bugs that had resulted from their use. Some time after after that, Barbara Liskov gave a talk about both theoretical and practical problems with the whole notion.
In The Design and Evolution of C++, Bjarne concludes that: "In retrospect I think that protected
is a case where I let 'good arguments' and fashion overcome my better judgment and my rules of thumb for accepting new features."
Bottom line: I'd have second and third thoughts about making your data protected
. It may look like a good idea now, but maintenance may be a rather different story.
Upvotes: 9
Reputation: 7855
I think giving subclasses access to your data is OK if you're not exposing this class as a library for others to subclass from. If you really want or need to hide the actual implementation of data from your subclasses, though, you can make mData
private and create accessors to it that are protected:
class Base {
protected:
// figure out what interface you want for your subclasses:
// do they need the whole enchilada? or can you give them
// a few more targeted kinds of modification routines?
// one example:
void add_data(const std::string& d) { mData.push_back(d); }
private:
std::vector<std::string> mData;
};
Upvotes: 0
Reputation: 5579
One design to consider is making mData private, and adding protected methods to Base that provide common manipulations to the data that can then be used by Dr1 and Dr2.
But there are plenty of times it makes more sense to leave mData as a protected member. The best approach will very much depend on the details of your class.
Upvotes: 3
Reputation: 7985
As long as it makes sense for all derived classes to have the member it makes good sense to put it in the Base class.
Reasons I see for not putting it there are:
#include <string>
and <vector>
.Upvotes: 1