Search code examples
c++inheritancec++17variantincomplete-type

Can I store subclass instances inside a superclass instance?


I want to create a tree structure with my classes so that I may update an object and then its children recursively.

My first idea was to add a variant list to the superclass so that every subsequent derived class can also store a list of children (thereby forming the tree structure). I tried implementing something like the following code, but keep getting errors when attempting to add Subclass A and B to the variant.

Is it possible to store subclasses within a superclass? Is this this even correct approach?

If there is a way to fix the code or another way to obtain the functionality please let me know!

#include <iostream>
#include <list>
#include <variant>

class SubClassA;
class SubClassB;

//-------------------------------------

class SuperClass {
public:
    std::list<std::variant<SuperClass, SubClassA, SubClassB>> children;
    
    void update() {
        // do X
        updateChildren();
    }

protected:
    void updateChildren() {
        for (auto &varObj : children) {
            std::visit([](auto& child) {child.update(); }, varObject);
        }
    }
};
    
//-------------------------------------

class SubClassA : public SuperClass {
public:
    void update() {
        // do Y
        updateChildren();
    }
};
    
//-------------------------------------

class SubClassB : public SuperClass {
public:
    void update() {
        // do Z
        updateChildren();
    }
};

Solution

  • The problem is that the definition of updateChildren() appears too early, before subclasses are defined. As a result, incomplete types are used in a context that requires complete ones.

    One possible solution is to put the definition of SuperClass::updateChildren() at the very end:

    class SuperClass {
        // ...
        void updateChildren();  // declaration only
    };
        
    class SubClassA : public SuperClass {/* ... */};
    class SubClassB : public SuperClass {/* ... */};
    
    void SuperClass::updateChildren() {
        // ...
    }