Home > Back-end >  How to get all child objects of a class
How to get all child objects of a class

Time:11-10

Is it possible to retrieve a list of child objects (of a cetain type) of an object ?

For example in this code I have an App with several available Commands. A function print all availible commands this way the user knows what he can do.
I want to iterate over each object of type Command found in App to print his doc, this way the doc updates itself automatically every time a Command is added in App.

class Command {
public:
    std::string Name;
    std::string Description;
    virtual void Compute() = 0;
};

class StartCommand : public Command {
    std::string Name = "start";
    std::string Description = "Start the process";
    virtual void Compute() {
        // Code to start the process
    }
};

class StopCommand : public Command {
    std::string Name = "stop";
    std::string Description = "Stop the process";
    virtual void Compute() {
        // Code to stop the process
    }
};

class App {
public:
    StartCommand StartCommand;
    StopCommand StopCommand;

    void PrintAvailibleCommands() {
        std::cout << "All availible commands are: " << std::endl;
        for (Command command : this.GetObjects<Command>()) {
            std::cout << command.Name << ": " << command.Description << std::endl;
        }
    }
};

It's the this.GetObjects<Command>() function which does not exist and which I would like to implement.

Do you have an idea ?

CodePudding user response:

This may solve your problem.

#include <cassert>
#include <cstring>
#include <iostream>
#include <vector>

using namespace std;

class Command {
  public:
    std::string Name;
    std::string Description;
    Command(std::string Name, std::string Description)
        : Name(Name), Description(Description) {}
    virtual void Compute() = 0;
};

class StartCommand : public Command {
  public:
    StartCommand() : Command("start", "Start the process") {}
    virtual void Compute() {
        // Code to start the process
    }
};

class StopCommand : public Command {
  public:
    StopCommand() : Command("stop", "Stop the process") {}
    virtual void Compute() {
        // Code to stop the process
    }
};

class App {
  public:
    template <typename T> void regCommand() { commands.push_back(new T); }

    App() {
        regCommand<StartCommand>();
        regCommand<StopCommand>();
    }

    vector<Command *> commands;

    void PrintAvailableCommands() {
        std::cout << "All available commands are: " << std::endl;
        for (Command *command : commands) {
            std::cout << command->Name << ": " << command->Description
                      << std::endl;
        }
    }
};

int main() {
    App app;

    app.PrintAvailableCommands();

    return 0;
}

CodePudding user response:

Often, I find it easier to put something into a collection directly when I want it to be there at some point.

#include <iostream>
#include <tuple>
#include <string>

struct Command {
    std::string Name;
    std::string Description;
    virtual void Compute() = 0;
};

struct StartCommand : Command {
    std::string Name = "start";
    std::string Description = "Start the process";
    virtual void Compute() {
        // Code to start the process
    }
};

struct StopCommand : Command {
    std::string Name = "stop";
    std::string Description = "Stop the process";
    virtual void Compute() {
        // Code to stop the process
    }
};

struct App {
    std::tuple<StartCommand, StopCommand> commands{};

    template<class Cmd>
    static void PrintCommand(const Cmd &cmd) {
        std::cout << cmd.Name << ": " << cmd.Description << std::endl;
    }

    void PrintAvailibleCommands() {
        std::cout << "All available commands are: " << std::endl;
        std::apply([](const auto &...cmds) { (PrintCommand(cmds), ...); }, commands);
    }
};
  • Related