按名称获取指向数据成员的指针

时间:2016-03-01 19:03:53

标签: c++

假设我的班级有一个整数数据成员:

class MyClass {

public:
    MyClass();

private:
    int my_int;
}

现在构建时,我希望收到一个数据类型,名称和值,所有都被编码为字符串:

public MyClass(string type, string name, string value) { ... }

根据类型和名称,在构造时将该值分配给我的数据成员。类似于:

public MyClass(string type, string name, string value)
{
    this->parse(type, name, value);
}

private parse(string type_, string name_, string value_)
{
    if (type_=="int")
    {
        int* int_ = getDataMember(name_);
        (*int_)=atoi(value_);
    }
    else ....
}

所以现在当我声明MyClass c("int","my_int","5")时,c将被初始化,其my_int数据成员的值设置为5.

问题是我不知道如何实现getDataMember(字符串名称)。但它显然会返回一个指向名称“name”的数据成员的指针。

1 个答案:

答案 0 :(得分:3)

虽然这不是C ++应该如何使用,但它并非完全不可能。

#include <string>
#include <map>

class MyClass {

public:
    MyClass(const std::string& type, const std::string& name, const std::string& value);

private:
    void parse(const std::string& type_, const std::string& name_, const std::string& value_);
    template <typename T>
    T* getDataMember(const std::string& name);

    int my_int;
    double my_double;
    char my_char;
    std::map<std::string, char*> members; //Map of strings to member memory locations
};

MyClass::MyClass(const std::string& type, const std::string& name, const std::string& value)
{
    //List of members will have to be hardcoded
    members["my_int"] = reinterpret_cast<char*>(&my_int);
    members["my_double"] = reinterpret_cast<char*>(&my_double);
    members["my_char"] = reinterpret_cast<char*>(&my_char);
    this->parse(type, name, value);
}

template <typename T>
T* MyClass::getDataMember(const std::string& name) {
    return reinterpret_cast<T*>(members[name]); //Will need to handle invalid names
}

void MyClass::parse(const std::string& type_, const std::string& name_, const std::string& value_)
{
  if (type_=="int")
  {
    int* int_ = getDataMember<int>(name_);
    (*int_)=atoi(value_.c_str());
  }
}

int main(void) {

    MyClass c("int","my_int","5");

    return 0;
}

我们的想法是保持map引用string成员地址。使用string访问地图将返回与string对应的成员的地址。但是,当将新成员引入该类时,必须对此map进行硬编码。此外,getDataMember函数必须处理将无效名称传递给类的情况。

<强>低效率

string比较从根本上来说很慢。比较发生了 当你将成员插入map时,当你要去的时候 通过您的parse函数尝试识别类型,以及何时 你在地图上搜索正确的密钥。

摆脱硬编码的可能方法

假设有一种方法可以在没有硬编码的情况下填充地图。这将涉及了解班级中存在哪些数据成员。由于C ++中似乎没有这样的功能,我们必须解析文件,或者至少解析包含该类的文件部分。但是,我们需要在编译文件之前完成此操作。这给我们留下了两个选择:

  1. 在编译时执行,这涉及使用预处理程序指令。不幸的是,我不知道如何利用预处理器指令来这样做。
  2. 编写一个外部可执行文件,用于解析项目/工作区中的文件,以识别类的数据成员,并继续在类的构造函数中附加成员映射的填充。即通过外部可执行文件自动完成地图填充过程。然后,我们可以确保在通过预构建事件构建项目时始终运行此外部可执行文件。
  3. <强>结论

    我认为最好找到你想要解决的问题的另一种方法,或者使用另一种语言,因为似乎C ++不是为此而构建的。

    考虑您的真正问题

    我相信您正在寻找的解决方案称为反序列化。

    class MyClass {
    public:
        void Deserialize(XMLParser xml);
    
    private:
        int my_int;
        double my_double;
        char my_char;
    };
    
    void MyClass::Deserialize(XMLParser xml) {
        while(xml.ReadLine() != "MEMBERS"); //Advances the XML parser to the line that specifies the members
        //Proceed to deserialize the members in order
        //This requires the file to list the members in the correct order
        my_int = atoi(xml.ReadLine().c_str());
        my_double = atof(xml.ReadLine().c_str());
        my_char = atoi(xml.ReadLine().c_str());
    }