変数値に基づいて C++ 関数を慣用的に呼び出すにはどうすればよいでしょうか?

StackOverflow https://stackoverflow.com/questions/3418700

  •  26-09-2019
  •  | 
  •  

質問

データ型があるとします。 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++ 機能は使用していません。

このコードをより良く書くにはどうすればよいでしょうか?

ありがとう、ボダ・シド。

役に立ちましたか?

解決

コードは 2 つまたは 3 つの値については問題ありませんが、値が数百ある場合は、より強力な何かが必要になります。考えられる解決策は 2 つあります。

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

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

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

他のヒント

一言で

:継承

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

あなたが初期化呼び出したいところはどこでもそれからちょうど正しくポインタや仕事への多型のための参照を持っていることを確認します:

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

を使用enum値によって索引付けされるルックアップテーブル(機能のすべてが同一の署名を有すると仮定して)、すなわち:

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

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

この初期化は本当に唯一の違いであれば、私は確信して、他のイディオムは、状況を改善するじゃない。

それでも同様の場合/ elseブロック、どこかで羽目になるだろうようにします。<

あなたは、ツリーからのサブクラス化し、ツリーオブジェクトの右側の並べ替えを作成...しかし、あなたはまだインスタンス化するかを区別するために必要があると思いますができ/ P>

これは、あなたがサブクラス化し、それらの間の違いを制定する仮想関数を使用する必要があります複数の異なるいただきたいだけ初期化よりも存在する場合には、言っています。

そして、あなたはあなたのタグでそれを指摘しているので、テンプレートの道ます:

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;
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top