C++ 插件的“最适合”动态类型匹配

2024-05-14

我有一个几乎所有东西都是插件的架构。该架构以图形用户界面为基础,其中每个插件都由一个“表面”(即用户可以通过其与插件交互的 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.


一种选择是在您的插件基类中有一个函数:

virtual std::string id() const { return "Plugin"; }

哪些派生类可以重写,例如 Grandson 知道其基类是 Mother,因此可能会编写以下代码:

override std::string id() const { return "Grandson " + Mother::id(); }

这样,当你打电话时id()在插件上,您会得到诸如“孙子母亲插件”之类的信息。你可以把它扔掉std::stringstream ss(id);, us a while (ss >> plugin_id),并寻求使用plugin_id作为表面容器中的钥匙......

我不认为你会找到一种使用方法typeid or dynamic_cast一样灵活,一样typeid不会告诉你基类(*),并且dynamic_cast必须知道它将在编译时测试的类型。我假设您希望能够使用新插件,并更改 id->surface 映射的某些文件或其他配置,而无需编辑代码......

(*) 如果您准备采用非标准并且它符合您的可移植性要求,C++:使用 typeinfo 测试类继承 https://stackoverflow.com/questions/11491076/c-using-typeinfo-to-test-class-inheritance记录获取基类的方法typeinfo在运行时。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++ 插件的“最适合”动态类型匹配 的相关文章

  • 使用 CLion 进行 OpenCV Windows 设置

    我想在 Windows 上为 CLion IDE 设置 OpenCV 我尝试使用 OpenCV 3 1 和 2 4 得到相同的结果 我有 Windows 10 64 位 CLion 使用 cygwin 环境 到目前为止我做了什么 1 从Op
  • CMake 找不到请求的 Boost 库

    既然我已经浏览了其他人的解决方案几个小时 但找不到适合我的问题的正确答案 我想将我的具体问题带给您 我正在尝试使用 CMake 构建 vsomeip 为此 我之前构建了 boost 1 55 但是 我在 CMake 中收到以下错误 The
  • 检测wlan是否关闭

    任何人都可以给我一个提示 如何在 Windows Phone 上以编程方式检测 C 8 1 应用程序 不是 8 0 是否启用 禁用 WLAN 我不想更改这些设置 只是需要知道 该解决方案是一个 Windows 8 1 通用应用程序 Wind
  • CSharpRepl emacs 集成?

    我碰巧知道莫诺CSharpRepl http www mono project com CsharpRepl 是否有 emacs csharp 模式使用它在一个窗口中运行 REPL 并像 python 模式一样在另一个窗口中编译 运行 C
  • 运行需要 MySql.Data 的内置 .NET 应用程序

    我在运行我编写的内置 NET 应用程序时遇到问题 我的应用程序使用最新的 MySql 连接器 该连接器安装在我的系统上 当我尝试将其添加为引用时 该连接器显示为 NET 4 Framwork 组件 当我在环境中以调试模式运行应用程序时 一切
  • C# 5 async/await 线程机制感觉不对?

    为什么让调用线程进入异步方法直到内部 等待 一旦调用异步方法就生成一个线程 这不是更干净吗 这样您就可以确定异步方法会立即返回 您不必担心在异步方法的早期阶段没有做任何昂贵的事情 我倾向于知道某个方法是否要在 我的 线程上执行代码 不管是堵
  • 使用 LINQ 更新 IEnumerable 对象的简单方法

    假设我有一个这样的业务对象 class Employee public string name public int id public string desgination public int grade List
  • 搜索实体的所有字段

    我正在尝试在客户数据库上实现 多功能框 类型的搜索 其中单个查询应尝试匹配客户的任何属性 这是一些示例数据来说明我想要实现的目标 FirstName LastName PhoneNumber ZipCode Mary Jane 12345
  • 如何使用 NPOI 按地址(A1、A2)获取 Excel 单元格值

    我有一个 Excel 单元格地址 例如 A1 A2 如何使用 C 中的 NPOI 框架以编程方式访问此单元格 我找到的一些 Java POI 示例代码 CellReference cr new CellReference A1 row my
  • 从BackgroundWorker线程更新图像UI属性

    在我正在编写的 WPF 应用程序中 我有一个 TransformedBitmap 属性 该属性绑定到 UI 上的 Image 对象 每当我更改此属性时 图像就会更新 因此显示在屏幕上的图像也会更新 为了防止在检索下一张图像时 UI 冻结或变
  • Project Euler #8,我不明白我哪里出了问题[关闭]

    Closed 这个问题是无法重现或由拼写错误引起 help closed questions 目前不接受答案 我正在做项目欧拉第八题 https projecteuler net problem 8 其中我得到了这个大得离谱的数字 7316
  • 如何从 Rx Subscribe 回调异步函数?

    我想回调 Rx 订阅中的异步函数 例如 像那样 public class Consumer private readonly Service service new Service public ReplaySubject
  • 英文日期差异

    接近重复 如何计算相对时间 https stackoverflow com questions 11 how do i calculate relative time 如何在 C 中计算某人的年龄 https stackoverflow c
  • CUDA 8 编译错误 -std=gnu++11

    我正在尝试转换一些代码以使用 CUDA 并且我认为我遇到了兼容性问题 我们使用CMake 这些是我使用的 gcc 和 CUDA 版本 gcc version gcc Ubuntu 5 4 0 6ubuntu1 16 04 5 5 4 0 2
  • 如何调试 .NET 运行时中的内部错误?

    我正在尝试调试一些处理大文件的工作 代码本身works 但 NET 运行时本身会报告零星错误 对于上下文 这里的处理是一个 1 5GB 文件 仅加载到内存中一次 在循环中处理和释放 故意尝试重现此否则不可预测的错误 我的测试片段基本上是 t
  • 如何在 winforms 应用程序的主屏幕显示之前显示欢迎屏幕?

    我想在应用程序启动时加载欢迎屏幕 然后用户单击欢迎屏幕上的按钮 然后关闭欢迎屏幕 最后显示主屏幕 static void Main startup method being called Application EnableVisualSt
  • C++ 中 void(*)() 和 void(&)() 之间的区别[重复]

    这个问题在这里已经有答案了 在此示例代码中 func1是类型void int double and funky是类型void int double include
  • 如何将 SQL“LIKE”与 LINQ to Entities 结合使用?

    我有一个文本框 允许用户指定搜索字符串 包括通配符 例如 Joh Johnson mit ack on 在使用 LINQ to Entities 之前 我有一个存储过程 该存储过程将该字符串作为参数并执行以下操作 SELECT FROM T
  • 为什么匹配模板类上的部分类模板特化与没有模板匹配的另一个部分特化不明确?

    这个问题可能很难用标题中的句子来描述 但这里有一个最小的例子 include
  • 使用未分配的局部变量

    我遇到了一个错误 尽管声明了变量 failturetext 和 userName 错误仍然出现 谁能帮帮我吗 Use of Unassigned local variable FailureText Use of Unassigned lo

随机推荐

  • 移动浏览器中的 React 性能

    我有一个组件 表 其中包含许多行 其中包含数据编辑 其掩码形式为contenteditable 可以选择所有字段并同时更改所有行 在桌面上它运行得相当快 但在 iPhone 6 上我有不真实的滞后 Safari 每次操作都会挂起 20 秒
  • 在 for 循环中访问 itertools 产品的元素

    我有一个列表列表 是附加 itertools 产品的一些其他结果的结果 我想要的是能够使用 for 循环访问列表列表中列表的每个元素 但我无法访问所有元素 我只能访问最后一个列表的元素 结果是一个非常巨大的列表列表 例如 1 2 4 3 6
  • iPhone 点击时使 div 变暗

    当您的 div 附加了点击处理程序时 当点击该 div 时 iPhone 会使该 div 变暗 作为点击指示器 示例 在移动 Safari 上查看http jsbin com awejo3 4 http jsbin com awejo3 4
  • titledBorder 标题中的图标

    您好 是否可以在 titledBorder 的标题中放置一个图标 例如以下代码 import java awt GridLayout import javax swing JFrame import javax swing JLabel i
  • 有没有办法拉伸整个显示图像以适应给定的分辨率?

    我最近一直在使用pygame制作游戏 遇到了一个小问题 基本上 我希望能够将屏幕上的整个图像 我已经传输到它的所有内容 拉伸到用户将窗口大小调整到的分辨率 我在 pygame 和堆栈溢出的文档中搜索了很多 但我似乎找不到答案 这可能吗 我的
  • 在 Chapel 中计算矩阵的 rowSums

    继续我的教堂冒险 我有一个矩阵A var idx 1 n var adom idx idx var A adom int populate A var rowsums idx int 填充行和的最有效方法是什么 The 最有效率的解决方案很
  • Android计算两个日期之间的天数

    我编写了以下代码来查找两个日期之间的天数 startDateValue new Date startDate endDateValue new Date endDate long diff endDateValue getTime star
  • 如何在 Rails 3.2.1 版本中注释 Rails 模型

    我正在尝试遵循一些在线教程来在 Rails 中注释我的模型 然而 似乎所有教程都在谈论过时的注释版本或不正确的安装 这真是一团糟 到目前为止我已经尝试过以下方法 1 在 Gemfile 中添加此内容 gem annotate 2 4 0 2
  • 元素不适应 Firefox 上的

    使用 ES6 ish D3js 模块运行 Angular 6 应用程序会导致 Firefox 出现问题 Chromium Chrome Safari 和 IE Edge 工作正常 伪代码看起来类似于 生产代码可以在下面找到
  • 更改 WizardStep 按钮文本

    如何重命名每个按钮的文本 默认 步骤 1 到 步骤 n WizardStep 对于整个Wizard完成按钮的文本可以通过设置属性来设置finishButtonText 但没有类似的属性WizardStep 没有标准的方法 这是我实现它的方法
  • Angular - 为每个请求设置标头

    我需要在用户登录后为每个后续请求设置一些授权标头 要为特定请求设置标头 import Headers from angular2 http var headers new Headers headers append headerName
  • BigQuery 中使用 GROUPBY 的百分位函数

    在我的人口普查表中 我想按州分组 并为每个州获取县人口中位数和县数量 在 psql redshift 和 Snowflake 中 我可以这样做 psql gt SELECT state count county PERCENTILE CON
  • jquery ajax加载后丢失CSS

    大家知道如何解决 load Ajax 请求后的 css 问题吗 例如 如果我想从网页加载 DIV 在我的 Ajax 请求之后 container load path to div div id 我丢失了与该 div 关联的所有 css 和脚
  • 2D morton 码编码/解码 64 位

    如何将给定 x y 的莫顿代码 z 顺序 编码 解码为 32 位无符号整数 生成 64 位莫顿代码 反之亦然 我确实有 xy2d 和 d2xy 但仅适用于 16 位宽的坐标 产生 32 位莫顿数 在网上查了很多 但没有找到 请帮忙 如果您可
  • 为什么 clang 使用 -O0 生成低效的 asm(对于这个简单的浮点和)?

    我正在 llvm clang Apple LLVM 版本 8 0 0 clang 800 0 42 1 上反汇编此代码 int main float a 0 151234 float b 0 2 float c a b printf f c
  • 使 Recyclerview 固定高度并可滚动

    已解决以下检查答案 所以我试图为我的 Android 应用程序创建评论功能 我想在 recyclerview 中显示评论 然后在 recyclerview 下方有一个按钮和文本视图来添加评论 我想让 recyclerview 具有一定的高度
  • 如何使用 PowerShell 查找 CPU 和 RAM 使用情况?

    我试图让 PowerShell 提供 RAM 和 CPU 使用情况 但我无法弄清楚要使用哪个 WMI 类 我的计算机有两个处理器 因此拥有这两个处理器的信息会很有用 您还可以使用 Get Counter cmdlet PowerShell
  • libxml2 xmlChar * 到 std::wstring

    libxml2似乎将所有字符串存储在 UTF 8 中 如xmlChar xmlChar This is a basic byte in an UTF 8 encoded string It s unsigned allowing to pi
  • Windows 10 中的 npm 安装错误( npm install -g angular-cli )

    node v v4 5 0 npm v 5 0 1 有人在 Windows 10 中安装 angular cli 时遇到过这种问题吗 请尝试以下操作 step 0 运行这个命令 npm uninstall g angular cli npm
  • C++ 插件的“最适合”动态类型匹配

    我有一个几乎所有东西都是插件的架构 该架构以图形用户界面为基础 其中每个插件都由一个 表面 即用户可以通过其与插件交互的 UI 控件 表示 这些表面也是插件 每当添加新插件时 瘦主机都会自动确定哪个可用表面与其最匹配的 UI 如何在 C 中