Pregunta

Supongamos que tengo un enum TreeTypes { TallTree, ShortTree, MediumTree } tipo de datos.

Y tengo para inicializar algunos datos sobre la base de un tipo de árbol en particular.

En la actualidad he escrito este código:

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;
}

Pero esto es una especie de repetición de código estúpida. No estoy usando cualquiera de los poderosos C ++ capacidades como plantillas.

¿Cómo podría escribir el código mejor?

Gracias, Boda Cydo.

¿Fue útil?

Solución

Su código está bien para dos o tres valores, pero tienes razón, se necesita algo más industrial fuerza cuando tiene cientos de ellos. Dos soluciones posibles:

  • utilizar una jerarquía de clases, no enumeraciones - a continuación, puede utilizar las funciones virtuales y tienen la obra compilador qué función real a la llamada

  • crear un mapa de enumeración -> función, que de que arranque en el arranque - sus llamadas de función y luego convertido en algo así como map[enum]->func()

Las plantillas no funcionan tan bien aquí, ya que están tratando de tomar una decisión en tiempo de ejecución, mientras que las plantillas hacen sus cosas en tiempo de compilación.

Otros consejos

En una palabra: la herencia

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 */
    }
}

A continuación, dondequiera que usted desee llamar initialize sólo asegúrese de tener correctamente un puntero o una referencia para el polimorfismo de trabajo:

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();

Usar una tabla de búsqueda que está indexado por los valores de enumeración (suponiendo que todas las funciones tienen la misma firma), es decir:

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; 
} 

Trate de una sentencia 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;
}

Si esta inicialización es realmente la única distinción, entonces no estoy seguro de cualquier otro idioma mejoraría la situación.

Se podría subclase de árbol y crear el tipo correcto de objeto de árbol ... pero aún había necesidad de diferenciar los cuales uno para crear una instancia, por lo que aún acabaría con un similar si / else bloque, en alguna parte.

Dicho esto, si hay algo más que de inicialización que habíamos diferente, usted debe subclase y utilizar las funciones virtuales de promulgar las diferencias entre ellos.

Y la forma en la plantilla ya que ha señalado que en sus etiquetas:

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 {
    // (...)
};

De esa manera usted tiene clases separadas para cada tipo de árbol que se puede acceder por el puntero de base. Envolviéndolos en la clase de árbol le permiten hacer esto:

Tree<Tall> tall_tree;
Tree<Short> short_tree;
Tree<Medium> medium_tree;
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top