简体   繁体   中英

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 ;)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM