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++ 功能,例如模板。

我怎样才能更好地编写这段代码?

谢谢,博达赛多。

4

6 回答 6

18

您的代码对于两个或三个值是可以的,但是您是对的,当您拥有数百个值时,您需要更具工业实力。两种可能的解决方案:

  • 使用类层次结构,而不是枚举 - 然后您可以使用虚函数并让编译器计算出要调用的实际函数

  • 创建一个枚举映射 -> 函数,你在启动时初始化它 - 你的函数调用然后变成类似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 */
    }
}

然后,无论您想调用初始化,只要确保有一个指针或引用,多态性才能正常工作:

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 回答