Konrad
Konrad

Reputation: 163

How to use one variable for a parent and derived class

I have a a base class and a derived class. The derived class has some additional functionality, and the user can switch between which class they're accessing.

class BaseClass {
private:
    string valid_operations[2] = {"%", "#"};
};

class DerivedClass : BaseClass {
private:
    string valid_operations[4] = {"!", "q", "%", "#"};
};

What I'm trying to do is instantiate a single object, and have the user be able to switch between these two objects interchangeably.

For example:

BaseClass obj;
string input;
while (true) {
    cin >> input;
    if (input == "switch")
      obj = DerivedClass();
    else
      obj.apply_action(input);
}

Is there a way to do this in C++? Also, is there a way I can declare valid_operations in DerivedClass to be {"!", "q"} + BaseClass.valid_operations?

Upvotes: 1

Views: 76

Answers (2)

jignatius
jignatius

Reputation: 6484

You could declare the function apply_action() as a virtual function in the base class. You can then override the function in your derived class and make use of polymorphism.

class BaseClass {
public:
    BaseClass(std::set<std::string> actions) : valid_operations(std::move(actions)) {}

    virtual void apply_action(std::string action)
    {
        if (IsValid(action))
        {
            //Do stuff
        }
    }

protected:
    bool IsValid(const std::string& action)
    {
        return valid_operations.find(action) != std::end(valid_operations);
    }

private:
    std::set<std::string> valid_operations;
};

class DerivedClass : public BaseClass {
public:
    DerivedClass(std::set<std::string> actions) : BaseClass(actions) {}

    virtual void apply_action(std::string action) override 
    {
        if (IsValid(action))
        {
            //Do stuff
        }
    }

};

In your main() function or wherever you want to use these classes you can create instances like this:

BaseClass base({ "%", "#" });
DerivedClass derived({ "!", "q", "%", "#" });

Using one BaseClass* pointer you can switch to use either one of these objects. This is how polymorphism works: same name but different behaviour depending on the actual object used. Use a BaseClass* pointer and point to either base or derived.

Upvotes: 1

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726559

You can't do it with an array variable, but if you opt for a vector, you could declare it in the base, and initialize in the protected constructor, like this:

class BaseClass {
private:
    std::vector<string> valid_operations;
protected:
    BaseClass(std::vector<string> vo) : valid_operations(vo) {}
public:
    void ShowValidOperations() {
        for (string op : valid_operations) {
            std::cout << op << " ";
        }
        std::cout << std::endl;
    }
};

class OptionOneDerived : public BaseClass {
public:
    OptionOneDerived() : BaseClass({"%", "#"}) {
    }
};

class OptionTwoDerived : public BaseClass {
public:
    OptionTwoDerived() : BaseClass({"!", "q", "%", "#"}) {
    }
};

int main() {
    BaseClass *b;
    OptionOneDerived a;
    b = &a;
    b->ShowValidOperations();
    OptionTwoDerived c;
    b = &c;
    b->ShowValidOperations();
    return 0;
}

Note that rather than using one derived class the example sets up a base that has no operations of its own, and relies on the subclass to provide the operation list in the constructor.

Also note that the implementation allocates derived classes in the main using automatic storage for expediency. An actual implementation would almost certainly use dynamic allocation with operators new and delete instead.

Upvotes: 1

Related Questions