如何将字符串变成引用?

时间:2016-04-06 08:40:08

标签: c++ qt

  

我已经研究过了,但这不是我想要的:Convert string to variable name or variable type

我有代码读取ini文件,将数据存储在QHash表中,并检查散列键的值(见下文),如果值为“1”,则将其添加到World。

代码示例:

World theWorld;
AgentMove AgentMovement(&theWorld);

if(rules.value("AgentMovement") == "1")
      theWorld.addRule(&AgentMovement);

INI文件:

AgentMovement=1

我想要做的是,从INI文件中动态读取并设置对硬编码变量的引用。

for(int j = 0; j < ck.size(); j++)
    if(rules.value(ck[j]) == "1")
        theWorld.addRule("&" + ck[j]);
                             ^
                             = &AgentMovement

如上所述,您如何将字符串转换为引用?

2 个答案:

答案 0 :(得分:1)

这是编程中的一个常见主题:一个值只能是一个集合中的一个(可以是一个枚举,一组有限的整数,或一组可能的字符串值,甚至是一些按钮) GUI)用作执行某种动作的标准。简单的方法是对复杂类型使用开关(对于原子类型)或if / else链。这就是你目前正在做的事情,并且它没有任何问题:

if(rules.value(ck[j]) == "1") theWorld.addRule(&AgentMovement);
else if(rules.value(ck[j]) == "2") theWorld.addRule(&AgentEat);
else if(rules.value(ck[j]) == "3") theWorld.addRule(&AgentSleep);
// etc.
else error("internal error: weird rules value %s\n", rules.value(ck[j]));

这种模式的主要优点在于我的经验,它非常清楚:任何人,包括你在一年内,立即了解正在发生的事情,并立即看到哪些标准导致了哪些行动。调试也是微不足道的,这可能是一个令人惊讶的优势:你可以打破一个特定的行动,只有在那个行动。

主要缺点是可维护性。如果使用相同的标准(枚举或其他)在不同位置的不同事物之间切换,则必须维护所有这些位置,例如当添加新的枚举值时。动作可能带有声音,图标,状态更改,日志消息等。如果这些不是同时发生的(在同一个开关中),你最终会在动作枚举上多次切换(或者如果/ then / else则超过字符串值)。在这种情况下,最好将连接到操作的所有信息捆绑在数据结构中,并将结构放在map / hash表中,并将操作作为键。所有交换机都崩溃为单个呼叫。这种映射的编译时初始化可能如下所示:

struct ActionDataT { Rule rule; Icon icon; Sound sound; };
map<string, AcionDataT> actionMap 
  = {
        {"1", {AgentMovement, moveIcon, moveSound} }
        {"2", {AgentEat,      eatIcon,  eatSound } } ,
        //
    };

用法就像

for(int j = 0; j < ck.size(); j++)
    theWorld.addRule(actionMap[rules.value(ck[j])].rule);

在其他地方,例如:

if(actionFinished(action)) removeIcon(actionMap[action].icon);

这很优雅。它演示了软件设计的两个原则:1。“计算机科学中的所有问题都可以通过另一个间接层次来解决”(David Wheeler),以及2.通常可以在更多数据或更多代码之间进行选择。简化方法是面向代码的,映射方法是面向数据的。

如果交换机出现在多种情况下,数据中心主义方法是必不可少的,因为每次编码都会成为维护的噩梦。

请注意,使用数据中心方法在添加新操作时,不得触及任何使用操作的位置。这是必不可少的。该机制类似于(在原理上和实现中,实际上)虚拟成员函数的调用。调用代码不知道并且实际上并不真正感兴趣。责任转移到对象。调用代码可以在程序的生命周期中稍后执行动作,该程序在写入时不存在。相比之下,将它与具有许多显式切换的程序进行比较,其中在添加动作时必须检查每个用途。

数据中心主义方法所涉及的间接性是它的缺点,并且唯一的问题是不能通过另一层次的间接解决,正如Wheeler所说。代码变得更抽象,因此不太明显,难以调试。

答案 1 :(得分:0)

您必须自己提供从名称到对象的映射。我会将它包装成一个类,如下所示:

template <typename T>
struct ObjectMap {
    void addObject(std::string name,T* obj){
        m[name] = obj;
    }
    T& getRef(std::string name) const {
        auto x = m.find(name);
        if (x != m.end() ) { return *(x->second);}
        else { return dummy; }
    }
    private:
        std::map<std::string,T*> m;
        T dummy;
}

这种方法的问题在于,如果请求的对象实际上不在地图中,则必须决定该怎么做。引用总是必须引用某些东西(与可以是0的指针相反)。我决定将引用返回给虚拟对象。但是,您可能需要考虑使用指针而不是引用。另一种选择可能是在对象不在地图中时抛出错误。