首页 > 解决方案 > 如何通过 C++ 中的另一种通用方式访问类的 getter 和 setter 方法

问题描述

我希望能够通过另一个类分配和/或检索对象的值,我可以在其中声明我想访问哪些属性、它们的类型、访问私有属性值的方法和分配方法价值。

我想将属性名称和操作值的方法存储在哈希中,这样我可以使用其他实体的类值的通用形式,但我不知道是否可能(我想是这样),我不知道该怎么做。

下面的代码不起作用,它是基于我为实现解决方案所做的尝试。错误之一是:

error: no matching function for call to 'Test<unsigned int>::Test(C&, const char [2], unsigned int (C::*)() const, void (C::*)(unsigned int))'
     auto t1 = new Test<unsigned int>(c, "a", &C::getA, &C::setA);

在代码片段下方

#include <string>
#include <map>

class C {
public:
    unsigned int getA() const {
        return a;
    }

    void setA(unsigned int value) {
        C::a = value;
    }

    const std::string &getB() {
        return b;
    }

    void setB(const std::string &value) {
        C::b = value;
    }

private:
    unsigned int a;
    std::string b;
};

template<typename T>
class Test {
public:
    Test(T t, const std::string attribute, const T (*getter)(), void (*setter)(T)) : t(t), attribute(attribute),
                                                                                      getter(getter), setter(setter) {}

    const std::string &getAttribute() const {
        return attribute;
    }

private:
    T t;
    std::string attribute;

    const T (*getter)();

    void (*setter)(T t);
};


int main(int argc, char **argv) {
    C c;
    auto t1 = new Test<unsigned int>(c, "a", &C::getA, &C::setA);
    auto t2 = new Test<std::string>(c, "b", &C::getB, &C::setB);
    std::map<std::string, std::string *> map;
    
    map.insert({t1.getAttribute, t1});
    map.insert({t2.getAttribute, t2});
}

所以基本上我有两个问题,可以这样做吗?如果是这样,如何?

例如,在这种情况下,如果我需要检索“a”(变量)t1 的值,我想转到地图并使用测试类 getter 的函数指针。

基于此,我将为 json 等实现解析器功能。

标签: c++

解决方案


我做过类似的事情;我有许多变量(不同类型),我想通过一个界面进行修改。我传递了一个字符串,我的班级将把它翻译成一个值来分配给连接的变量。

我首先创建一个带有虚函数的类:

struct param_assign_base
{       
    virtual void assign(void* param, const char* value) = 0;
};

// Declare the concrete class.
template<typename p_type>
struct param_assign;

然后我为此创建专门的实例,例如用于bool类型变量:

template<>
struct param_assign<bool> : param_assign_base
{
    void assign(void* param, const char* value)
    {
        *static_cast<bool*>(param) = extract_bool(value);
    }

    bool extract_bool(const char* value)
    {
        // make a return value that will be assigned to the connected variable.
    }
};

然后我填充一张地图:

using param_map_type = std::map<
    std::string, 
    std::pair<void*, params::param_assign_base*>>;

param_map_type populate()
{
    param_map_type param_map;
    param_map["a"] = std::make_pair(&a, new param_assign<bool>);
    param_map["b"] = std::make_pair(&b, new param_assign<char*>);
    param_map["c"] = std::make_pair(&c, new param_assign<int>);

    // a more proper design wouldn't use new, it would 
    // use std::make_unique to avoid memory leaks.
}

然后我使用构造param_map变量来分配变量,例如:

param_map["a"].second->assign(param_map["a"].first, value_to_assign);

上面的行也可以放在一个函数中,这样你就可以避免重复param_map["a"]

这种设计的缺点是您将无法访问该变量,除非您可以在访问时显式转换其类型param_map["a"],因为在这种情况下它只是一个 void 指针。使用 map 时,每个条目都需要具有相同的类型,因此 map 无法区分类型。


推荐阅读