我有一个几乎所有东西都是插件的架构。该架构以图形用户界面为基础,其中每个插件都由一个“表面”(即用户可以通过其与插件交互的 UI 控件)表示。这些表面也是插件。每当添加新插件时,瘦主机都会自动确定哪个可用表面与其最匹配的 UI。如何在 C++ 中完成动态类型匹配是这个问题的主题。
目前,该架构是用 C# 实现的,严重依赖反射,正如您将看到的。然而,我现在正在为 C++ 重新设计整个东西,但由于 C++ 没有反射(并且因为我是 C++ 新手),我需要一些关于如何在没有反射的情况下最好地复制此功能的输入。
以下是目前在 C# 中的实现方式(简化和伪):
所有插件都是a的后代Plugin
class.
每个表面类型都标有“目标插件类型”,指示其设计的插件的最具体/最深入的后代。
最通用的表面是仅处理插件级别的表面(例如,仅显示名称标签)。这保证了所有插件至少有一个能够在屏幕上表示它们的表面,即使它不提供任何有用的交互方式。
我们将此称为“基线”表面类型PluginSurface
。如果 - 为了简洁起见(实际上它是通过类属性完成的) - 我们使用表面上的属性来指示它们的目标类型,我们会有
PluginSurface.TargetType = typeof(Plugin)
除非添加更多特定的表面,否则所有插件都将被分配此通用表面,无论它们位于插件继承层次结构中的哪个位置。
现在,假设我们添加一个名为 Father 的新插件类型,它派生自 Plugin:
Father : Plugin
然后我们添加更多一些,以创建一个小示例层次结构:
Mother : Plugin
Daughter : Father
Son1 : Mother
Son2 : Mother
Grandson : Son1
此时,所有这些都将通过通用的方式在屏幕上表示PluginSurface
。因此,我们创建额外的表面来更具体地处理新插件的功能(所有表面都源自 PluginSurface):
MotherSurface.TargetType = typeof(Mother)
GrandsonSurface.TargetType = typeof(Grandson)
由此看来,插件到表面的有效类型匹配应该是:
Father -> PluginSurface
Daughter -> PluginSurface
Mother -> MotherSurface
Son1 -> MotherSurface
Son2 -> MotherSurface
Grandson -> GrandsonSurface
好的,这就是我们期望最终得到的映射。本质上,匹配是作为主机中的静态函数实现的,该函数采用插件类型并返回最佳拟合表面的实例:
PluginSurface GetBestFitSurface(Type pluginType)
该函数迭代所有可用的表面并检查它们的TargetType
针对所提供的财产pluginType
。更具体地说,它检查 TargetType 是否IsAssignableFrom
插件类型。它创建所有积极匹配的列表。
然后需要缩小候选名单的范围最合适的。为此,我对可分配性进行了类似的检查,但这一次所有候选人的 TargetType 之间,将每个候选者与其他候选者进行检查,并且对于每个候选者,我记下其 TargetType 可分配给其他候选者的 TargetType 数量。 TargetType 可分配(即强制转换)到大多数其他 TargetType 的候选者是最合适的。
后来发生的事情是,该表面成为相关插件的包装器,根据配合的紧密程度在屏幕上排列自身以反映它“理解”的插件的功能。 AGrandsonSurface
是专门设计来代表GrandSon
,所以它将是该插件的完整 UI。但Son1
and Son2
是“唯一”得到MotherSurface
,所以它们没有共同点的任何特征Mother
不会包含在他们的 UI 表示中(直到更专业的Son
界面制作完毕,此时that将是最合适的等等)。请注意,这是预期用途 - 通常,Mother 插件是abstract并且针对它的界面实际上是一个子接口,旨在包裹所有母亲的children。因此,单个界面为一整类类似功能的插件提供了 UI。
如果没有反射的支持,如何在 C++ 中最好地完成此操作?
我认为挑战在于将 C++ 与 C# 进行模拟Type.IsAssignableFrom(Type)
两种类型都是动态归因的..我正在朝以下方向寻找dynamic_cast
and typeid
,但到目前为止我还没有牢牢掌握如何去做。任何有关架构、模式或实现细节的提示将不胜感激。
编辑1:我认为我已经解决了这里的主要问题(请参阅下面我自己的答案,其中包括[非常]粗糙的C++实现),但可能有更好的模式。随意将其撕开。
编辑 2:在此处找到的后续问题中提出了改进的模型:C++ 中的“穷人的反思”(又名自下而上的反思) https://stackoverflow.com/questions/21057938/poor-mans-reflection-in-c.