【问题标题】:Using objects and object functions through variables通过变量使用对象和对象函数
【发布时间】:2013-09-29 14:30:11
【问题描述】:

程序背景:用户只能输入两个词的string - 一个动词和一个名词。我将此字符串标记为vector,并将tokens[0] 与允许动词的vector 进行比较,将tokens[1] 与允许名词的vector 进行比较。

现在,我正在尝试找到一种方法,只允许对某些名词执行某些动词。例如,写“take book”会给出一条消息(或其他),说它是允许的,但写“take door”则不会。到目前为止,我已经为每个可能的动词创建了一个带有 bool 值的 class 对象(例如,在 class Object 内,我可以为 m_take = true 创建一个 Object book,或者为 Object door 创建一个 false )。

但是,我无法将这些对象与用户输入关联起来。例如,我希望能够做这样的事情:
1)用户输入“动词名词”,作为tokens[0]tokens[1]进入标记向量。
2) 程序检查输入是否包含可接受的单词(单独)。
3) 考虑到getstat() 是检索对象上可能执行的操作的布尔值的函数,程序检索tokens[1].getstat(tokens[0]),如果true,则执行tokens[0].tokens[1]()(例如book.take())。这样我就可以在我的main() 中只有一个if 循环,它可以被所有合法的动词和名词使用,而无需列出ifelse if 等的无限列表,手动考虑每个选项。

对不起,如果这令人困惑。我知道不可能将变量用作对象名称,但我确信有更好的方法来做到这一点,而不是在考虑动词和名词的每一个混合和匹配的循环中循环。我目前正在尝试每个 3 个,但是一旦我开始工作,我计划扩展它,如果我必须对每个可能的动词和名词进行多次硬编码,那么跟踪每一个变化将是一场噩梦源代码。 (另外,很抱歉没有发布整个源代码 - 这是一个非常长的文件!) 感谢您在正确方向上的任何帮助/提示!

【问题讨论】:

  • 您可能想了解指向成员的指针 的概念(也可能是关于虚函数)。

标签: c++ class object


【解决方案1】:

您可以对这类东西使用运行时多态性,可以使用 virtual 方法或 C++11 std::function 和 lambdas。

你显然必须重新设计你的“token”系统。


虚拟方法示例:

struct Object
{ 
    virtual void onTake() { }
    virtual void onOpen() { }
};

struct Door : public Object 
{
    bool open{false};
    void onTake() override { say("I can't take the door!"); }
    void onOpen() override { say("The door is now open."); open = true; }
};

struct Book : public Object
{
    void onTake() override { say("I put the book in my backpack."); }
    void onOpen() override { say("I open the book. All the pages are blank."); }
};

C++11 lambda 示例:

struct Object
{ 
    std::function<void()> onTake, onOpen;
};

struct Door : public Object 
{
    bool open{false};
    Door() 
    {
        onTake = []{ say("I can't take the door!"); };
        onOpen = []{ say("The door is now open."); open = true; };
    }
};

struct Book : public Object
{
    Book() 
    {
        onTake = []{ say("I put the book in my backpack."); };
        onOpen = []{ say("I open the book. All the pages are blank."); };
    }
};

// You can also avoid creating new classes
Object bananaPrototype; 
bool eaten{false};
bananaPrototype.onTake = []{ say("I put the banana in my backpack."); };
bananaPrototype.onOpen = [eaten] mutable 
{ say("I eat the banana. Yum."); eaten = true; };

【讨论】:

  • 这非常有用,谢谢!我以前从未使用过任何这些(之前也没有使用过structs),但它似乎可以满足我的需要,所以我会调查一下。谢谢!不过,只有一个问题,我如何将其链接到用户输入?如何让程序从string“门”调用struct Door,或从string“取”调用onTake?我是否必须创建一个 ifs 列表来为所有可能的对象分配一个给另一个,还是有更简单的方法?
  • 好的,我一直在研究这个,试图让它适用于我正在做的事情,这可能是一个非常愚蠢的问题,但你所说的“说”是什么意思,如在void onTake() override { say("I can't take the door!"); } ?我试图用谷歌搜索它是否是我未包含的内容的一部分,但在任何地方都找不到。谢谢:)
  • 都是伪代码。 say 是一个虚构的函数,它说明了一些事情。改用cout&lt;&lt; 或任何你有的东西。
  • 啊,有道理 - 感觉这是一个愚蠢的问题 :) 谢谢!
【解决方案2】:

在没有看到代码的这种不平凡的情况下很难给出建议,但据我了解,您最好考虑放弃硬编码方法,即 book.take()。 尝试编写更通用的代码,至少像 book.action(actions::kTake) 这样的代码。

【讨论】:

    【解决方案3】:

    正如你所说,tokens[0].tokens[1]() 没有做你想做的事 - 程序运行时函数和变量的名称不可用。

    您可以尝试使用地图。 objects 可以是带有对象名称键的映射。这些值 (objects[token[0]]) 又将是其他映射,这些映射将是执行您想要的功能 (objects[token[0]][token[1]])。

    这是一个例子:

    #include <unordered_map>
    #include <string>
    #include <iostream>
    
    using namespace std;
    
    void read_fn()
    {
        cout << "You read the book";
    }
    
    int main()
    {
        unordered_map <string, unordered_map <string, void (*)()>> lookup;
    
        unordered_map <string, void (*)()> book_lookup;
    
        book_lookup["read"] = read_fn;
        lookup["book"] = book_lookup;
    
        lookup["book"]["read"]();
    }
    

    【讨论】:

    • 谢谢!我没想到我可以使用地图。我将尝试在地图中配对动词和名词,然后在地图中查找输入词以查看是否找到相关配对。
    猜你喜欢
    • 2015-10-08
    • 1970-01-01
    • 2013-07-19
    • 2019-01-26
    • 1970-01-01
    • 2013-03-12
    • 1970-01-01
    • 1970-01-01
    • 2015-12-31
    相关资源
    最近更新 更多