Search code examples
c++oopopenframeworks

pass any object to function to create this object


I'm making a small generative video layering software using openframeworks and c++. To this effect I have one main class, one layer class and a lot of different types of video/simulations class. I need to make it so that when I press a key, a different simulation is loaded.

I have two questions :

  1. How can I access a list of all my simulation classes ?
  2. Following up, how can I feed one choice from this list into a function that can take any type of object and initiate it ?

I made a drawing instead of using to code brackets to have all 3 blocks on the same horizontal level (actual code is underneath).

enter image description here

Here's the main.cpp and the layer.cpp in code for clarity :

// main.cpp
void ofApp::setup(){
    layer1.setup();
    layer2.setup();
    layer3.setup();
}

void ofApp::update(){
    layer1.update(); 
    layer2.update(); 
    layer3.update(); 
}

void ofApp::draw(){
    layer1.draw(); 
    layer2.draw(); 
    layer3.draw(); 
}

void ofApp::keyPressed(int key){
    switch (key)
    {
    case '1':
        // get first class from list of classes
        layer1.changeSim(); // input first class from list of simulation classes
        break;
    default:
        break;
    }
}

and the layer.cpp

void layer::setup(){
simulation = new Simulation();  // how do i initialize the Simulation variable if I dont know what type itll be ?
}

void layer::update(){
    simulation.update(); 
}

void layer::draw(){
    simulation.draw(); 
}

void layer::changeSim(){
    simulation = new Simulation(); // destroy old simulation and create new one, but will be of a different class
}

Solution

  • Best method to do this is to use something called the factory pattern.

    Basically, define a function that takes an argument of some defined type that can be used to figure out what kind of simulation you want, and then create that simulation and return a pointer to it.

    A simple version of it might look like this:

    enum SimulationType
    {
        Simulation_None,
        Simulation_Basic,
        Simulation_Complex,
    ...
    };
    
    Simulation* CreateSimulation(SimulationType Type)
    {
        switch(Type)
        {
        case Simulation_None:
        default:
            return nullptr;
        case Simulation_Basic:
            return new BasicSimulation();
        case Simulation_Complex:
            return new ComplexSimulation();
    ...
        }
    }
    
    ...
    
    void ofApp::keyPressed(int key){
        switch (key)
        {
        case '1':
            // get first class from list of classes
            layer1.changeSim(Simulation_Basic); // input first class from list of simulation classes
            break;
        default:
            break;
        }
    }
    
    ...
    
    void layer::setup(){
    simulation = CreateSimulation(Simulation_None);
    }
    
    void layer::changeSim(SimulationType Type){
        if(simulation) delete simulation;
        simulation = CreateSimulation(Type);
    }
    
    

    This is a simple example - you could also use a table indexed by SimulationType, an ordered map of SimulationType that references static constructor functions for each type, basically anything that associates an identifier with a constructor function.