Domanda

Supponiamo di avere un tipo di dati enum TreeTypes { TallTree, ShortTree, MediumTree }.

E devo inizializzare alcuni dati in base a un particolare tipo di albero.

Attualmente ho scritto questo codice:

int initialize(enum TreeTypes tree_type) {
    if (tree_type == TallTree) {
        init_tall_tree();
    }
    else if (tree_type == ShortTree) {
        init_short_tree();
    }
    else if (tree_type == MediumTree) {
        init_medium_tree();
    }
    return OK;
}

Ma questa è una specie di stupida ripetizione del codice.Non utilizzo nessuna delle potenti funzionalità C++ come i modelli.

Come potrei scrivere meglio questo codice?

Grazie, Boda Cydo.

È stato utile?

Soluzione

Il tuo codice va bene per due o tre valori, ma hai ragione, hai bisogno di qualcosa di più potente a livello industriale quando ne hai centinaia.Due possibili soluzioni:

  • usa una gerarchia di classi, non enumerazioni: puoi quindi usare funzioni virtuali e fare in modo che il compilatore capisca quale funzione effettiva chiamare

  • crea una mappa di enum -> funzione, che inizializzi all'avvio: le tue chiamate di funzione diventano qualcosa di simile map[enum]->func()

I modelli non funzionano così bene qui, perché stai cercando di prendere una decisione in fase di esecuzione, mentre i modelli fanno il loro lavoro in fase di compilazione.

Altri suggerimenti

In una parola: l'eredità

class Tree { public: virtual void initialize() = 0; }

class ShortTree : public Tree {
public:
    virtual void initialize(){
        /* Short Tree specific code here */
    }
}

class MediumTree : public Tree {
public:
    virtual void initialize(){
        /* Medium Tree specific code here */
    }
}

class TallTree : public Tree {
public:
    virtual void initialize(){
        /* Tall Tree specific code here */
    }
}

Quindi, ovunque si desidera chiamare inizializzazione solo assicurarsi di avere correttamente un puntatore o un riferimento per il polimorfismo al lavoro:

Vector<Tree*> trees;
trees.push_back(new SmallTree());
trees.push_back(new MediumTree();
trees.push_back(new TallTree();

// This will call the tree specific code for each tree in the vector
for(vector<Tree*>::iterator tree = trees.begin(); tree!=trees.end(); ++tree)
    tree->initialize();

Utilizzare una tabella di ricerca che viene indicizzato dai valori enum (supponendo tutte le funzioni hanno la stessa firma), cioè:

enum TreeTypes { TallTree, ShortTree, MediumTree, MaxTreeTypes }

typedef void (*p_init_func)(void); 

p_init_func initialize_funcs[MaxTreeTypes] =
{
    &init_tall_tree, 
    &init_short_tree,
    &init_medium_tree
};

int initialize(enum TreeTypes tree_type)
{ 
    initialize_funcs[tree_type]();
    return OK; 
} 

Prova un'istruzione switch:

int initialize(enum TreeTypes tree_type) {
    switch (tree_type) {
        case TallTree: 
            init_tall_tree();
            break;
        case ShortTree:
            init_short_tree();
            break;
        case MediumTree:
            init_medium_tree();
            break;
    }
    return OK;
}

Se questa inizializzazione è davvero l'unica distinzione, quindi non sono sicuro di qualsiasi altro idioma migliorerebbe la situazione.

Si potrebbe ereditare da Albero e creare il giusto tipo di oggetto albero ... ma avresti ancora bisogno di differenziare quale per istanziare, quindi faresti ancora vento con un simile if / else blocco, da qualche parte.

Detto questo, se non v'è più di un semplice inizializzazione Sarebbe diverso, è necessario creare una sottoclasse e utilizzare le funzioni virtuali di emanare le differenze tra di loro.

E il modo in modello dal momento che avete indicato nel tag:

enum TreeTypes { Tall, Short, Medium };

struct TreeBase {
    // (...)
};

struct TallTree : public TreeBase {
    // (...)
};

struct ShortTree : public TreeBase {
    // (...)
};

struct MediumTree : public TreeBase {
    // (...)
};

template<TreeTypes N_type = Tall>
struct Tree : public TallTree {
    // (...)
};

template<>
struct Tree<Short> : public ShortTree {
    // (...)
};

template<>
struct Tree<Medium> : public MediumTree {
    // (...)
};

In questo modo si ha classi separate per ciascun tipo di albero che può essere letta da puntatore base. avvolgendoli in classe Tree ti permette di fare questo:

Tree<Tall> tall_tree;
Tree<Short> short_tree;
Tree<Medium> medium_tree;
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top