在c ++中将字符串/字符转换为类成员/方法

时间:2013-10-24 05:45:14

标签: c++ class class-members

有没有办法将字符串或字符转换为类成员/成员函数以动态访问它们?

代表。这个特殊的代码,

 #include <iostream>
 #include <map>

 using namespace std;

 class agnt {
 public:
 int x, y;
 agnt(int a=0, int b=0) : x(a), y(b) {}
 };


 int main() {
      map<int,agnt> agntID;
      agnt temp;
      temp.x=1;
      temp.y=5;

      agntID[1]=temp;

      for(char tmp='x'; tmp<'z'; tmp++) {
         cout<<agntID[1].tmp<<'\n';     //Here I get the following error: tmp is
         }                              //not a member of class agnt
 }

有没有办法转换字符'tmp',使其被识别为类成员?任何提示或解决方案将不胜感激。

4 个答案:

答案 0 :(得分:2)

C ++没有任何introspection,所以不可能。

但是,您可以通过使用包含名称作为键的另一个std::map来“破解”它,并且值是对变量的引用:

agnt temp;

std::unordered_map<char, int&> variable_map = {
    { 'x', temp.x },
    { 'y', temp.y }
};

variable_map['x'] = 123;
std::cout << variable_map['y'] << '\n';

它通常不值得,因为它更有效。特别是如果你想为多个变量做这个(因为每个结构变量都需要自己的映射)。

答案 1 :(得分:1)

没有

C ++没有内省和反思能力。您必须自己编写这种动态访问权限。

在某些情况下,手动编码的合理替代方法是使用外部模式文件来描述C ++类,然后自动生成类以及内省和反射代码。你不能使用模板来做到这一点,因为在这个领域完全没有C ++的元编程能力。

通过直接解析.h来生成代码通常会困难得多,因为C ++语法有多复杂(即使编译器制造商花了相当多的时间才能在很大程度上同意有效的C ++)代码和什么不是。)

您可以使用模板来简化发布,但仍然可以手动执行:

template<typename T, typename C>
std::map<std::string, T C::*>& attribute_map() {
    static std::map<std::string, T C::*> m;
    return m;
}

template<typename C>
struct Published {
    template<typename T>
    T& attribute(const std::string& name) {
        std::map<std::string, T C::*>& m = attribute_map<T, C>();
        typename std::map<std::string, T C::*>::const_iterator i=m.find(name);
        if (i == m.end()) {
            throw std::runtime_error("Attribute not present");
        } else {
            return static_cast<C *>(this)->*i->second;
        }
    }
};

对于每个属性,您需要明确地“发布”它

template<typename T, typename C>
void publish(const std::string& name, T C::*mp) {
    attribute_map<T, C>()[name] = mp;
}

鉴于上述样板代码,您可以创建一个类并通过派生Published<Class>来发布它的一些成员:

struct MyClass : Published<MyClass> {
    int a;
    double b;
    std::string c;

    MyClass(int a, double b, const std::string& c)
        : a(a), b(b), c(c)
    {
    }
};

然后,您需要在程序开始时只调用一次publish函数才能动态访问属性:

int main(int argc, const char *argv[]) {
    publish("a", &MyClass::a);
    publish("b", &MyClass::b);
    publish("c", &MyClass::c);

    MyClass m1(3, 4.5, "This is a test");
    MyClass m2(6, 7.8, "This is another test");

    std::cout << m1.attribute<int>("a") << "\n";
    std::cout << m2.attribute<std::string>("c") << "\n";
    return 0;
}

答案 2 :(得分:1)

你不能在C ++中这样做,因为它是一种静态类型的语言。获得此类行为的一种方法是提供访问包装器:

template <char c>
struct getter {
};


template <>
struct getter<'x'> { 
   static int get(const agnt &theAgnt) {
      return theAgnt.x;
   }
};


template <>
struct getter<'y'> { 
   static int get(const agnt &theAgnt) {
      return theAgnt.y;
   }
};

template <char c>
int get(const agnt &theAgnt) {
    return getter<c>::get(theAgnt);
}

并致电:

agnt temp;
//... set members
std::cout << get<'x'>(temp) << std::endl;

但是,for循环不会按预期方式工作,因为模板参数需要在编译时确定。此外,您不能只请求任何旧的东西,除非您在非专业化get中定义getter函数,该函数返回某种NULL指示符,如INT_MIN

然而 ,这实际上是一个非常黑客的东西含糊类似于动态语言。但它与引用temp.x并没有什么不同。相反,您应该尝试遵循C ++约定并享受静态类型!

答案 3 :(得分:1)

虽然回答NO的每个人都是正确的......但这并不能说明整个故事。 语言中没有任何内容允许您这样做,但这并不意味着环境不允许这样做。

例如,在vxworks上,您可以调用symFindByName()来查找函数,变量或任何其他符号,然后可以通过它提供的指针调用该函数。但这依赖于OS API,可能是vxworks链接器工作方式的副作用

其他操作系统可能具有类似的功能。