gpt4 book ai didi

c++ - C++中的“Poor Man'反射”(又名自下而上的反射)

转载 作者:塔克拉玛干 更新时间:2023-11-03 02:02:51 27 4
gpt4 key购买 nike

我正在C++中实现一种超模块化体系结构的基本反射(reflection),该构架实际上将所有功能都作为插件加载并在运行时动态解释。由于系统具有结构自组织的独特元素,因此组件需要一些相互检查的方法(例如,需要这种反射风格的情况的示例,请参见此问题:“Best fit” dynamic type matching for plugins in C++)。

到目前为止,该体系结构是用C#开发的,但我现在正在研究如何用C++来实现。此时,我已基于以下模型为“穷人的倒影”创建了骨架:

一个Type类,用于保存相关的类信息:

namespace Reflection {

class Type {
public:
Type(Object &, string, bool(*)(Type *));
~Type();
Object & RefObj();
string Name();
bool IsAssignableFrom(Type *);
private:
Object & _refObj;
string _name;
bool(*_isAssignableFrom_Handler)(Type *);
};

}

还有一个 Object类,反射模型中的所有参与者都将从该类下降:
class Object {
public:
Object();
virtual ~Object();
virtual string ToString();
virtual Reflection::Type * GetType();
static Reflection::Type * Type();
static bool IsAssignableFrom(Reflection::Type *);
private:
static Object _refObj;
static Reflection::Type _type;
};

..定义如下:
string Object::ToString() { return GetType()->Name(); }

// all derived classes must implement the equivalent of this:

Reflection::Type * Object::GetType() { return &_type; }

Object Object::_refObj;

Reflection::Type Object::_type(_refObj, "Object", Object::IsAssignableFrom);

Reflection::Type * Object::Type() { return &_type; }

bool Object::IsAssignableFrom(Reflection::Type * type) {
return dynamic_cast<Object*>(&type->RefObj()) != nullptr;
}

请注意,我只需要在自己的类层次结构(全部都继承自 Object)中进行反射即可。因此,以上代码现在使我能够:
  • 获取任何实例的类型:instance.GetType()
  • 获取任何类的类型:class::Type()
  • 比较类型:例如(instance.GetType() == class::Type())(instanceA.GetType() == instanceB.GetType())
  • 执行运行时检查以查看是否可以将一个Type实例分配给另一个(即,动态地带有两个“未知”。C++中的所有内置选项似乎都需要在编译时知道至少一个Types),基本上等同于is和推论继承关系的关键:(instanceA.GetType()->IsAssignableFrom(instanceB.GetType()))
  • 通过类型
  • 动态引用抽象类型
  • 获取类型(即类)的一致,友好名称

  • 这足以满足我的迫切需求,并且可以通过向Type类添加功能来扩展功能范围(下一个功能就是可以在给定Type实例的情况下实例化类的功能-与.Net的 Activator.CreateInstance类似)。但是与“适当的”反射(reflect)不同,后者本质上是一种自上而下的方法,其中有关类的[元]信息是在编译器级别收集/集中管理的,它是手动进行的,并且是自下而上的,将知识分发到对象本身中并给出他们在运行时彼此之间进行通信的一种方式。因此,要使其工作,此系统中包含的每个类都需要实现与 Object类相同的成员和功能,以封装自身的相关方面以进行“导出”。举个例子, Plugin类看起来像这样(定义):
    Reflection::Type * Plugin::GetType() { return &_type; }

    Plugin Plugin::_refObj;

    Reflection::Type Plugin::_type(_refObj, "Plugin", Plugin::IsAssignableFrom);

    Reflection::Type * Plugin::Type() { return &_type; }

    bool Plugin::IsAssignableFrom(Reflection::Type * type) {
    return dynamic_cast<Plugin*>(&type->RefObj()) != nullptr;
    }

    如您所见,它实际上与其父类 Object相同。几乎所有这些功能仅因其类类型(和名称)而异。

    所以我有几个问题。
  • 第一个是是否有任何方法可以通过编译器宏或巧妙的继承/模板化等方法来简化此过程,因为将有很多重复。它让我印象深刻,因为它可以实现自动化?像提取类的名称(可能包括 namespace )并从中生成代码一样?或基于一个或两个变量的某些源代码摘要模板(会想到类名)。
  • 第二个更通用(这是我包括所有这些代码的原因)。我使用C++的时间很短,所以我感觉很讨厌,并认为我的方法和实现细节可能很幼稚。如果有其他人在相似的架构上工作/有相似的需求,也许他们可以分享经验(甚至指出我的模型/代码中的缺陷)。

  • 有关需要这种反射风格的情况的示例,请参见以下问题: “Best fit” dynamic type matching for plugins in C++

    更新:

    就第一个问题而言,这就是我最终要做的事情:

    我制作了两个宏,一个用于.h文件,一个用于.cpp文件。现在,我要做的就是在类声明中添加 REFLECTION_H(TYPE_NAME),并在类定义中添加 REFLECTION_CPP(TYPE_NAME),所有反射样板都会自动包含在内。然后,我可以像往常一样添加特定于类的成员,而不必考虑反射,因为知道所需的所有管道均已就绪并且一切正常。例如,在当前的实现中,新的 Surface类现在看起来像这样:

    Surface.h:
    class Surface : public Plugin
    {
    REFLECTION_H(Surface)
    public:
    // ...class specific public member declarations...
    private:
    // ...class specific private member declarations...
    };

    Surface.cpp:
    REFLECTION_CPP(Surface);

    Surface::~Surface() {}

    // ...class specific member definitions...

    宏的定义如下:
    #define REFLECTION_H(TYPE_NAME) \
    public:\
    virtual ~TYPE_NAME();\
    static Reflection::Type& Type();\
    private:\
    virtual Reflection::Type& _getType();\
    static TYPE_NAME _refObj;\
    static Reflection::Type _type;\
    static bool IsAssignableFrom(Reflection::Type&);\
    static plugin_ptr CreateInstance();

    #define REFLECTION_CPP(TYPE_NAME) \
    Reflection::Type& TYPE_NAME::Type() { return _type; }\
    Reflection::Type& TYPE_NAME::_getType() { return _type; }\
    TYPE_NAME TYPE_NAME::_refObj;\
    Reflection::Type TYPE_NAME::_type(_refObj, #TYPE_NAME, true, IsAssignableFrom, CreateInstance);\
    bool TYPE_NAME::IsAssignableFrom(Reflection::Type& type) { return dynamic_cast<TYPE_NAME*>(&type.RefObj()) != nullptr; }\
    plugin_ptr TYPE_NAME::CreateInstance() { return plugin_ptr(new TYPE_NAME); }

    最佳答案

    Python
    由于您提到自己在Visual Studio中,因此我在下面编写的宏可能对您不起作用(根据我的经验,宏可能是令人讨厌的跨平台)。因此,这是一个Python示例,您可以将其作为预构建脚本运行,以基于文本文件中的名称生成* .cpp文件。
    create_classes.py

    template = """Reflection::Type * {0}::GetType() {{
    return &_type;
    }}

    // static type info

    {0} {0}::_refObj;

    Reflection::Type {0}::_type(_refObj, "{0}", {0}::IsAssignableFrom);

    Reflection::Type * {0}::Type() {{
    return &_type;
    }}

    bool {0}::IsAssignableFrom(Reflection::Type * type) {{
    return dynamic_cast<{0}*>(&type->RefObj()) != nullptr;
    }}
    """

    if __name__ == '__main__':
    with open('classes', 'r') as classes:
    for class_name in classes:
    class_name = class_name.strip()
    with open('{0}.cpp'.format(class_name), 'w') as source:
    source.write(template.format(class_name))
    (文本文件)
    Blossom
    Bubbles
    Buttercup
    它将使用上面的模板创建Blossom.cpp,Bubbles.cpp和Buttercup.cpp。您可以自行决定将正确的名称添加到“类”文本文件中。 :)
    我确定您可以修改此设置,以将每个定义分为* .hpp和* .cpp,请告诉我这是否有帮助。
    C++宏
    尽管我不喜欢宏(并且仍然建议不要使用宏!),但是这些宏会生成您的代码。我还没有对它们进行彻底的测试,因此它们可能会将您射中。它们的命名也很差(不清楚宏的名称),但这就是这个主意。
    macros.cpp
    #define GET_TYPE_METHOD(X) \
    Reflection::Type * X::GetType() { return &_type; }

    #define GET_REF_OBJ(X) X X::_refObj;

    #define GET_UNDERSCORE_TYPE(X) \
    Reflection::Type X::_type(_refObj, #X, X::IsAssignableFrom);

    #define GET_TYPE(X) \
    Reflection::Type * X::Type() { return &_type; }

    #define GET_IS_ASSIGNABLE_FROM(X) \
    bool X::IsAssignableFrom(Reflection::Type * type) { return dynamic_cast<X*>(&type->RefObj()) != nullptr; }

    GET_TYPE_METHOD(Keeler)
    GET_REF_OBJ(Keeler)
    GET_UNDERSCORE_TYPE(Keeler)
    GET_TYPE(Keeler)
    GET_IS_ASSIGNABLE_FROM(Keeler)
    如果运行 g++ -E macros.cpp,则将获得预处理器输出。查看预处理器的想法:
    $ g++ -E macros.cpp
    # 1 "macros.cpp"
    # 1 "<command-line>"
    # 1 "/usr/include/stdc-predef.h" 1 3 4
    # 1 "<command-line>" 2
    # 1 "macros.cpp"
    # 16 "macros.cpp"
    Reflection::Type * Keeler::GetType() { return &_type; }
    Keeler Keeler::_refObj;
    Reflection::Type Keeler::_type(_refObj, "Keeler", Keeler::IsAssignableFrom);
    Reflection::Type * Keeler::Type() { return &_type; }
    bool Keeler::IsAssignableFrom(Reflection::Type * type) { return dynamic_cast<Keeler*>(&type->RefObj()) != nullptr; }
    这是否符合您的需求?

    关于c++ - C++中的“Poor Man'反射”(又名自下而上的反射),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21057938/

    27 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com