Search code examples
c++forward-declaration

How to access forward declaration in C++ class?


The following code works, but it is not very readable to have methods separated from each state of this state machine:

struct Base {
    virtual Base* next() = 0;
};

struct StateA : public Base {
    Base* next();
};

struct StateB : public Base {
    Base* next();
};

StateA stateA;
StateB stateB;

Base* StateA::next() {
    return &stateB;
}

Base* StateB::next() {
    return &stateA;
}

I would rather prefer to have this structure, unfortunately, I don't know if it is possible in C++ to foward declare stateA and stateB:

struct Base {
    virtual Base* next() = 0;
};

struct StateA : public Base {
    Base* next() { return &stateB; }
};

struct StateB : public Base {
    Base* next() { return &stateA; }
};

StateA stateA;
StateB stateB;

Is it possible to keep the implementation of StateX along with their declaration?

I have tried to trick the compiler with this, but as guessed, it doesn't build:

struct Base {
    virtual Base* next() = 0;
};

struct StateA;
struct StateB;

extern StateA *stateAptr;
extern StateB *stateBptr;

struct StateA : public Base {
    Base* next() { return stateBptr; }
};

struct StateB : public Base {
    Base* next() { return stateAptr; }
};

StateA stateA;
StateB stateB;
StateA *stateAptr = &stateA;
StateB *stateBptr = &stateB;

Solution

  • The keyword extern is responsible for forward variable declarations. But it's can be used before their types are defined. You can split member function declarations and definitions.

    struct Base {
        virtual Base* next() = 0;
    };
    
    struct StateA : public Base {
        Base* next();
    };
    
    struct StateB : public Base {
        Base* next();
    };
    
    StateB stateB;
    StateA stateA;
    
    Base* StateA::next() { return &stateB; }
    Base* StateB::next() { return &stateA; }
    

    Or update your trick for using Base* pointers.

    struct Base {
        virtual Base* next() = 0;
    };
    
    extern Base *stateAptr;
    extern Base *stateBptr;
    
    struct StateA : public Base {
        Base* next() { return stateBptr; }
    };
    
    struct StateB : public Base {
        Base* next() { return stateAptr; }
    };
    
    StateA stateA;
    StateB stateB;
    Base *stateAptr = &stateA;
    Base *stateBptr = &stateB;
    

    But it does not improve readability in comparison with the first code, and conflicts with your sentence "it is not very readable".