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

Obtain a pointer to a data member by its name

本文关键字:数据成员 指针 取指 获取      更新时间:2023-10-16

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

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"的数据成员的指针。

虽然这不是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++中似乎没有这样的功能,因此我们必须解析文件,或者至少解析包含类的文件部分。但是,我们需要在编译文件之前完成此操作。这给我们留下了 2 个选择:

  1. 在编译时执行此操作,这涉及使用预处理器指令。不幸的是,我不知道任何利用预处理器指令来做到这一点的方法。
  2. 对解析项目/工作区中的文件的外部可执行文件进行编程,以标识类的数据成员,并继续在类的构造函数中追加成员映射的填充。 即通过外部可执行文件自动执行地图填充过程。然后,我们可以确保每当通过预构建事件构建项目时,始终运行此外部可执行文件。

结论

我认为最好找到另一种方法来解决问题,或者使用完全不同的语言,因为它似乎不是为此而构建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());
}