variables in abstract classes C++
I have an abstract class CommandPath, and a number of derived classes as below:
class CommandPath {
public:
virtual CommandResponse handleCommand(std::string) = 0;
virtual CommandResponse execute() = 0;
virtual ~CommandPath() {}
};
class GetTimeCommandPath : public CommandPath {
int stage;
public:
GetTimeCommandPath() : stage(0) {}
CommandResponse handleCommand(std::string);
CommandResponse execute();
};
All of the derived classes have the member variable 'stage'. I want to build a function into all of them which manipulates 'stage' in the same way, so rather than defining it many times I thought I'd build it into the parent class. I moved 'stage' from the private sections of all of the derived classes into the protected section of CommandPath, and added the function as follows:
class CommandPath {
protected:
int开发者_运维百科 stage;
public:
virtual CommandResponse handleCommand(std::string) = 0;
virtual CommandResponse execute() = 0;
std::string confirmCommand(std::string, int, int, std::string, std::string);
virtual ~CommandPath() {}
};
class GetTimeCommandPath : public CommandPath {
public:
GetTimeCommandPath() : stage(0) {}
CommandResponse handleCommand(std::string);
CommandResponse execute();
};
Now my compiler tells me for the constructor lines that none of the derived classes have a member 'stage'. I was under the impression that protected members are visible to derived classes?
The constructor is the same in all classes, so I suppose I could move it to the parent class, but I'm more concerned about finding out why the derived classes aren't able to access the variable.
Also, since previously I've only used the parent class for pure virtual functions, I wanted to confirm that this is the way to go about adding a function to be inherited by all derived classes.
Try this:
class CommandPath {
protected:
int stage;
public:
CommandPath(int stage_) : stage(stage_) {}
};
class GetTimeCommandPath : public CommandPath {
public:
GetTimeCommandPath(int stage_) : CommandPath(stage_) {}
};
(Omitted extra code for brevity).
You can't use the initializer list on a parent class' members, only the current one's. If that makes sense.
First of all: don't use protected
for attributes.
It may seem arbitrary, but the point is that it breaks encapsulation. Imagine that suddenly you realize what of space it is to use an int
when an unsigned short
would have done, so you go ahead and change CommandPath
.
Unfortunately, since all the classes deriving from CommandPath
could access stage
directly, there is a strong change the compiler will complain now: void changeStage(int&);
is no longer suitable for example, so you have to reword it... and it's messy.
Proper encapsulation requires that you don't expose your attributes: they are defined as private
and you never return handles to them. The idiomatic way is to provide Get
and Set
methods (you don't necessarily have to change their type, or you may provide overloads, etc...)
Also protected
is quite a bastard keyword, it does not protect much and the accessibility restriction it is supposed to define is weak:
class Base { protected: void specialMethod(); };
struct Derived: Base { void specialForward() { specialMethod(); } };
A simple case of deriving and it's now public, that's why it can't be used for encapsulation ;)
精彩评论