如何惯用地调用 C++基于变量值的函数?

发布于 2024-09-12 22:10:49 字数 517 浏览 9 评论 0原文

假设我有一个数据类型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++ 功能,例如模板。

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

谢谢,博达·西多。

Suppose I have a data type enum TreeTypes { TallTree, ShortTree, MediumTree }.

And I have to initialize some data based on one particular tree type.

Currently I have written this code:

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

But this is some kind of stupid code repetition. I am not using any of the powerful C++ capabilities like templates.

How could I write this code better?

Thanks, Boda Cydo.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

悲喜皆因你 2024-09-19 22:10:49

您的代码对于两个或三个值来说是可以的,但是您是对的,当您有数百个值时,您需要更具工业强度的东西。两种可能的解决方案:

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

  • 创建枚举映射 ->函数,您在启动时初始化 - 您的函数调用将变成类似 map[enum]->func()

模板在这里效果不佳,因为您试图在以下位置做出决定运行时,而模板在编译时完成它们的工作。

Your code is OK for two or three values, but you are right, you need something more industrial strength when you have hundreds of them. Two possible solutions:

  • use a class hierarchy, not enums - you can then use virtual functions and have the compiler work out which actual function to call

  • create a map of enum -> function, which you initialise at startup - your function calls then become something like map[enum]->func()

Templates don't work so well here, because you are trying to make a decision at run-time, whereas templates do their stuff at compile-time.

森林迷了鹿 2024-09-19 22:10:49

一言以蔽之:继承

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

In one word: inheritance

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

Then wherever you want to call initialize just make sure to have a pointer or a reference for polymorphism to work correctly:

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();
烟雨扶苏 2024-09-19 22:10:49

使用由枚举值索引的查找表(假设所有函数具有相同的签名),即:

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

Use a lookup table that is indexed by the enum values (assuming all of the functions have the same signature), ie:

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; 
} 
青柠芒果 2024-09-19 22:10:49

以及模板方式,因为您已经在标签中指出了它:

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;

And the template way since you have pointed it in your tags:

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

That way you got seperate classes for each tree type which can be accessed by base pointer. Wrapping them into Tree class let you do this:

Tree<Tall> tall_tree;
Tree<Short> short_tree;
Tree<Medium> medium_tree;
桃扇骨 2024-09-19 22:10:49

如果这个初始化确实是唯一的区别,那么我不确定任何其他习惯用法会改善这种情况。

您可以从 Tree 继承并创建正确类型的树对象...但是您仍然需要区分要实例化的树对象,因此您仍然会在某处得到类似的 if/else 块。

也就是说,如果不仅仅是初始化不同,您应该子类化并使用虚函数来体现它们之间的差异。

If this initialization is really the only distinction, then I'm not sure any other idiom would improve the situation.

You could subclass from Tree and create the right sort of tree object...but you'd still need to differentiate which one to instantiate, so you'd still wind up with a similar if/else block, somewhere.

That said, if there is more than just initialization that'd different, you should subclass and use virtual functions to enact the differences between them.

凉世弥音 2024-09-19 22:10:49

尝试使用 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;
}

Try a switch statement:

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;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文