Frage

Angenommen, ich einen Datentyp enum TreeTypes { TallTree, ShortTree, MediumTree } haben.

Und ich habe einige Daten zu initialisieren, basierte auf einem bestimmten Baumart.

Zur Zeit habe ich diesen Code geschrieben:

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

Aber das ist eine Art von dummer Code Wiederholung. Ich bin nicht von der leistungsfähigen C ++ Funktionen wie Vorlagen.

Wie kann ich diesen Code besser schreiben?

Danke, Boda cyclo.

War es hilfreich?

Lösung

Der Code ist in Ordnung für zwei oder drei Werte, aber du hast recht, müssen Sie etwas mehr industrielle Stärke, wenn Sie Hunderte von ihnen haben. Zwei mögliche Lösungen:

  • eine Klassenhierarchie verwenden, nicht Aufzählungen - Sie können dann virtuelle Funktionen nutzen und haben die Compiler Arbeit eigentliche Funktion aufzurufen, die

  • erstellen eine Karte von ENUM -> Funktion, die Sie beim Start initialisieren - Ihre Funktion Anrufe werden dann so etwas wie map[enum]->func()

Vorlagen nicht so gut hier arbeiten, weil Sie eine Entscheidung zur Laufzeit zu machen versuchen, während Vorlagen ihre Sachen zur Compile-Zeit zu tun.

Andere Tipps

In einem Wort: Vererbung

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

Dann, wo immer Sie initialize nur anrufen möchten sicherstellen, dass richtig einen Zeiger oder eine Referenz für Polymorphismus zur Arbeit haben:

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

Verwenden Sie eine Lookup-Tabelle, die von den ENUM-Werte indiziert ist (vorausgesetzt, alle Funktionen die gleiche Signatur haben), dh:

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

Versuchen Sie, eine switch-Anweisung:

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

Wenn diese Initialisierung wirklich der einzige Unterschied ist, dann bin ich nicht sicher, ob anderes Idiom die Situation verbessern würde.

Sie könnten von Baum Unterklasse und die richtige Art von Baum-Objekt erstellen ... aber Sie würden immer noch zu unterscheiden müssen, die man zu instanziieren, so dass Sie immer noch mit einem ähnlichen aufzuwickeln würden, wenn / else-Block, irgendwo.

sagte, dass, wenn es mehr als nur die Initialisierung ist die unterschiedliche würde, sollten Sie eine Unterklasse und virtuelle Funktionen verwenden, um die Unterschiede zwischen ihnen zu erlassen.

Und die Vorlage Art und Weise, da Sie es in Ihren Tags darauf hingewiesen haben:

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

So können Sie separate Klassen für jede Baumart bekommen, die durch Basiszeiger zugegriffen werden kann. sie in Tree-Klasse Wrapping können Sie dies tun:

Tree<Tall> tall_tree;
Tree<Short> short_tree;
Tree<Medium> medium_tree;
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top