6

データ型があるとしますenum TreeTypes { TallTree, ShortTree, MediumTree }

そして、特定のツリータイプに基づいていくつかのデータを初期化する必要があります。

現在、私はこのコードを書いています:

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

しかし、これはある種の愚かなコードの繰り返しです。テンプレートのような強力なC++機能は使用していません。

どうすればこのコードをより良く書くことができますか?

ありがとう、BodaCydo。

4

6 に答える 6

18

コードは 2 つまたは 3 つの値に対しては問題ありませんが、そのとおりです。数百の値がある場合は、より工業的な強度が必要です。考えられる解決策は次の 2 つです。

  • 列挙型ではなくクラス階層を使用します。その後、仮想関数を使用して、コンパイラにどの実際の関数を呼び出すかを決定させることができます

  • enum -> function のマップを作成し、起動時に初期化します - 関数呼び出しは次のようになりますmap[enum]->func()

ここではテンプレートはあまりうまく機能しません。なぜなら、テンプレートはコンパイル時に処理を行うのに対し、実行時に決定を下そうとしているからです。

于 2010-08-05T20:06:30.887 に答える
8

一言で言えば:継承

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

次に、 initialize を呼び出したい場所で、ポリモーフィズムが正しく機能するためのポインターまたは参照があることを確認してください。

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();
于 2010-08-05T20:09:30.757 に答える
2

列挙値によってインデックス付けされたルックアップ テーブルを使用します (すべての関数が同じシグネチャを持っていると仮定します)。つまり、次のようになります。

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; 
} 
于 2010-08-05T20:11:57.160 に答える
1

そして、タグでそれを指しているので、テンプレートの方法:

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

そうすれば、ベースポインタでアクセスできるツリータイプごとに個別のクラスを取得できます。それらを Tree クラスにラップすると、次のことが可能になります。

Tree<Tall> tall_tree;
Tree<Short> short_tree;
Tree<Medium> medium_tree;
于 2010-08-05T20:46:29.777 に答える
0

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;
}
于 2010-08-05T20:07:01.323 に答える
0

この初期化が本当に唯一の違いである場合、他のイディオムが状況を改善するかどうかはわかりません。

Tree からサブクラス化して、適切な種類のツリー オブジェクトを作成することもできますが、インスタンス化するオブジェクトを区別する必要があるため、同様の if/else ブロックをどこかに配置することになります。

とはいえ、異なるのは初期化だけではない場合は、サブクラス化して仮想関数を使用して、それらの違いを制定する必要があります。

于 2010-08-05T20:07:54.567 に答える