2013-09-29 52 views
2

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

现在,我试图找到一种方法,只允许某些动词在某些名词上执行。例如,编写“take book”会给出一个消息(或其他),表示允许,但是写入“take door”不会。到目前为止,我为每个可能的动词创建了一个class对象,其值为bool(例如,在class Object内,我可以创建Object book,其中m_take = truefalseObject door)。

但是,我无法将这些对象与用户输入相关联。例如,我希望能够做到这样的事情:
1)用户输入“动词名词”,它进入标记向量tokens[0]tokens[1]
2)程序检查输入是否包含可接受的单词(单独)。
3)考虑getstat()是中检索一个物体上的可能的动作是可行的bool值的功能,该程序检索tokens[1].getstat(tokens[0]),如果true,执行tokens[0].tokens[1]()(例如book.take())。这样,我的main()中只能有一个if周期,可供所有法律动词和名词使用,而无需制定无限的if,else if等列表,手动考虑每个选项。

对不起,如果这一切混淆。我知道使用变量作为对象名称是不可能的,但我相信有一种更好的方法可以做到这一点,而不是在考虑动词和名词的每个混合和匹配的周期内进行循环。我现在正在尝试3个,但是一旦我得到这个工作,我打算扩展它,如果我必须多次硬编码每个可能的动词和名词,那么跟踪每个变化将是一场噩梦源代码。 (另外,抱歉没有发布整个源代码 - 这是一个非常长的文件!) 感谢任何帮助/提示正确的方向!

+0

您可能要在成员指针** **的概念读了(也许还对虚拟函数)。 –

回答

2

你可以使用运行时多态来处理这种东西,或者使用virtual方法或C++ 11 std::function和lambda。

您显然必须重新设计您的“令牌”系统。


虚拟方法例如:

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

这非常有用,谢谢!我从来没有使用过任何这个(之前没有使用'structs'),但它似乎会做我所需要的,所以我会研究它。谢谢!只是有一个问题,我如何将这个链接与用户输入相关联?如何让程序从'string'“门”调用'struct Door',或者从'string'中调用'onTake'“取”?我是否需要创建一个ifs列表来为所有可能的对象指定另一个,还是有一个更简单的方法? – Nicholas

+0

好的,我一直在考虑这个,试着让它适用于我正在做的事情,这可能是一个非常愚蠢的问题,但是,你说的“说”是什么意思,就像'void onTake()override {说(“我不能走门!”); ''?我试图谷歌它,看看它是我没有包括的东西的一部分,但无法在任何地方找到它。谢谢:) – Nicholas

+0

这都是伪代码。 “说”是一个虚构的功能,可以说某事。使用'cout <<'来替代或者你拥有的任何东西。 –

0

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

0

正如你所说,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"](); 
} 
+0

谢谢!我没有想过我可以使用地图。我会尝试在地图中配对动词和名词,然后在地图上查找输入单词以查看是否找到相关对。 – Nicholas