【发布时间】:2014-01-11 02:44:48
【问题描述】:
我在 C++ 中为超模块化架构实现了一些基本反射,其中几乎所有功能都作为插件加载并在运行时动态解释。由于系统有一个独特的结构自组织元素,因此组件需要一些相互检查的方法(有关需要这种反射风格的示例,请参阅此问题:“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()获取任意类的Type:
class::Type()比较类型:例如
(instance.GetType() == class::Type())或(instanceA.GetType() == instanceB.GetType())执行运行时检查以查看是否可以为一个类型实例分配另一个(即动态地,使用两个“未知数”。C++ 中的所有内置选项似乎都需要在编译时知道至少一种类型) , 基本上相当于
is和推断继承关系的关键:(instanceA.GetType()->IsAssignableFrom(instanceB.GetType()))按类型动态引用抽象类型
获取一致、友好的类型名称(即类)
这足以满足我的即时需求,并且可以通过向 Type 类添加功能来扩展功能范围(接下来是实例化仅给定 Type 实例的类的能力 - 类似于 .Net 的Activator.CreateInstance)。但与“正确”反射不同,后者本质上是一种自上而下的方法,其中关于类的 [元] 信息在编译器级别收集/集中管理,这是手动和自下而上完成的,将知识分配到对象本身并给出它们是在运行时相互通信的一种方式。因此,要实现这一点,该系统中包含的每个类都需要实现与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 相同。几乎所有这些函数仅因它们的类类型(和名称)而异。
所以我有几个问题。
第一个是是否有任何方法可以简化这一点,通过编译器宏或巧妙的继承/模板等,因为有/将会有很多重复。它让我觉得可以自动化?就像提取类的名称(可能包括名称空间)并从中生成代码一样?或者一些基于一个或两个变量的源代码 sn-p 模板(想到类名)。
第二个更通用(也是我包含所有这些代码的原因)。我只使用 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); }
【问题讨论】:
-
这是托管 C++ ala C++.NET 吗?
-
不,只是简单的 C++(尽管我可能(故意)使用 C# 中有关命名和格式等的一些约定,以使自己更舒服)。
-
C++ 的设计初衷并不是像 C# 或 Java 那样使用反射(即运行时类型信息)。
-
那么,您为什么不使用当今所有主要操作系统(以及次要操作系统)都可用的标准“组件架构”之一呢?或者也许这只是学习这些先进技术的练习?无论如何,我建议看看现有的 C++ 库,例如 ROOT.Reflex (root.cern.ch/drupal/content/reflex) 或 Boost.Reflex bytemaster.github.io/boost_reflect/index.html,尽管后者似乎已被放弃。
-
没人推荐crtp?我没有看到任何困难。
标签: c++ design-patterns plugins reflection types