Marked as Duplicate
Marked as Duplicate

Reputation: 1249

How to make a virtual function accept a data type defined only in derived classes?

I have a C++ class with two virtual functions that use an undefined State struct either as the return/parameter type. My problem is that the State structs are only defined in the derived classes and the base class knows nothing about it.

class Base {
    // Error: Identifier 'State' is undefined
    virtual void serialize(State& last_state) = 0;
    virtual State& getCurrentState() = 0;
};

class Derived : public Base {
    struct State { // Every derived class has different State fields
        int32_t x = 0;
        int32_t y = 0;
    } current_state;
    void serialize(State& last_state) override;
    State& getCurrentState() override;
}

Virtual data members aren't a thing, so I'm assuming I just can't define a struct twice. I've also thought that maybe I could create an empty base struct and have every derived classes' State inherit from it, but that doesn't seem like a very clean solution.

Some context for what I'm trying to do in case there's a completely different way this problem could be solved:

I have a map of objects inheriting from Base (std::unordered_map<int, std::shared_ptr<Entity>). I sometimes loop over the map and want to call serialize() and getCurrentState() for each object.
I don't know which derived object I'm accessing, so I can't just cast the base pointer to the derived one. I can't just call a derived classes' members through the base pointer, so what do I do?

Upvotes: 1

Views: 634

Answers (1)

n314159
n314159

Reputation: 5085

Virtual data members aren't a thing, so I'm assuming I just can't define a struct twice. I've also thought that maybe I could create an empty base struct and have every derived classes' State inherit from it, but that doesn't seem like a very clean solution.

That is indeed what you should do. I think it is cleaner, when you declare the base state as a protected class in Base, so

class Base {
protected:
    struct State{};
public:
    virtual void serialize(State& last_state) = 0;
    virtual State& getCurrentState() = 0;
};

class Derived : public Base {
public:
    struct State : Base::State { // Every derived class has different State fields
        int32_t x = 0;
        int32_t y = 0;
    } current_state;
    void serialize(Base::State& last_state) override; // Note that the Base:: is important, otherwise the function does not override
    State& getCurrentState() override; // You can add Base:: to the return type but you don't have to.
};

Upvotes: 4

Related Questions