为向量中的所有对象动态调用 C++ 类成员

Posted

技术标签:

【中文标题】为向量中的所有对象动态调用 C++ 类成员【英文标题】:Dynamically call C++ class members for all objects in a vector 【发布时间】:2015-01-11 20:04:58 【问题描述】:

我有一个问题,我正试图用一个非常不明显的解决方案来解决(至少对我而言)。假设我有一个简单的类

class Foo 
  private:
    int x, y, z;
  public:
    Foo(int x, int y, int z) : x(x), y(y), z(z) 

属性 x、y、z 也有公共的 getter 和 setter。

我有一个类封装了一个 Foo 的向量 Item,它初始化它们并赋予它们默认值等...

现在Store 正在被第三类Processor 修改。基本上我试图实现的行为如下:

Processor 有一个 std::function 向量,其中包含指向 Store 不同成员的指针,例如 ChangeItemSpecs()ChangeItemSourcing()。它是一个循环遍历并重复调用的列表。

Processor 在函数被调用后检查Store,如果它们是“好”的变化。例如,如果商店的总价值增加了​​,或者商店的运营成本降低了。我可能有不同的处理器来分析包含指向 Store 的不同成员的指针的模型,这些成员做不同的事情。或者可能是同样的事情,但只是运行不同的分析。

如果更改不利,Processor 应该“回滚”所做的更改。 这就是我在设计上苦苦挣扎的地方

最初我想以某种方式获取将要更改的项目的指针和索引,并让Processor 复制它们,因为Item 几乎只是比 POD 类高出一步。如果提议的更改不受欢迎,Processor 会将修改后的 Item 替换为原始的 Item 副本。但这非常低效,因为我有一个非常大的数据集。

我的问题归结为:我想要一种通用的方式来存储有关 Item(或一堆项目)的先前信息,如果 Processor 不喜欢改变。

我想过创建一个名为Change 的对象,其中Store 可以注册处理和回滚更改的成员,然后让Processor 存储Change 对象的数组。更改将有一个名为“proposeChange”和“回滚”更改的成员(是否存在适合“接受更改”的不同范例?)。然后Processor 将简单地循环遍历每个迭代的每个Change 项目并执行其操作。但这并不能真正解决管理回滚信息的问题。只是另一个抽象......

非常感谢任何帮助。我是否错误地处理了这个问题?有不同的看法吗?我该如何设计它?我真的不需要代码,除非它采用了 C++ 的一些深奥特性,或者非常先进——我只需要有关如何设计高效系统的指导。

其他cmets:

性能是关键。每个“商店”中可能有数十万甚至更多Items。因此,为什么我认为我首先建议的复制方法对性能的影响太大了。

它应该经得起简单的并行化。这意味着在 Model 中存储状态信息可能不是一个好主意(或者是吗?)。我想非常简单地并行化Processor 中的迭代。如果我忽略了某些事情并且这变得非常复杂,那么我们现在可以忘记这一点。

提前致谢!

【问题讨论】:

回滚让我觉得你应该看看en.wikipedia.org/wiki/Memento_pattern 能否详细说明StoreItem 之间的关系?我可以看到像 “Store 的不同成员,例如 ChangeItemSpecs()ChangeItemSourcing()“每个 Store 中可能有数十万甚至更多项目” 但我没有看到任何关于这种关系的明确描述。 一个商店除了包含许多Item对象的向量之外,还包含它自己的属性。商店也有公共成员,它们会返回有关项目的汇总统计信息,或提供对特定项目或项目的访问。也可以在商店中添加或删除项目。还有什么相关的吗? 【参考方案1】:

我认为您使用 Change 对象记录修改导致的更改的方法是一个很好的方向。

实际上,这是一种非常实用的方法,根据经验,并行喜欢功能。我不认为我完全理解您的模型,但为了简单起见,我们假设我们只有一个项目列表并且可以插入或删除项目。然后归结为两个简单的转换。

fins(L, i, X) — 插入项目 X 在位置 i 进入列表 L fdel(L, i) — 删除位置 i 处的项目列出 L

如你所见,fins-1 = fdel反之亦然。

使用composition,我们可以构建任意复杂的更改。另请注意,通常 (f1f2)−1 = f2-1f1-1 .

因此,一旦您确定了构成模型更改的基本操作并为每个操作定义了逆向操作,就可以将它们组合成一个复杂的更改,并通过以相反的顺序应用逆向操作来回滚。

如果你喜欢设计模式,这就是 Command 模式。转换对象的好处是它们通常非常简单,可以在需要时进行序列化和存储。

如果您想并行尝试多个更改,您甚至可以使用 Decorator 模式更进一步。您无需将更改直接应用于模型,而是创建一个装饰模型,该模型在每次调用接口函数时应用更改。因此,例如,如果您使用在 L 中的位置 i 处插入项目 X 的转换来装饰模型,则装饰器仅存储此信息。然后,如果对第 j 元素的请求,装饰器检查是否 j i,如果是,则简单地转发到现有模型。否则,如果 j > i,它会转发到模型请求元素 j – 1. 最后,如果 j = i,它返回自己的元素X。每个装饰器只需要存储转换,而不是整个模型。您可以将装饰器堆叠在一起以共享相同的更改。如果您发现更改变得更糟,只需处理掉装饰器,没人会注意到。如果您真的喜欢更改,可以将其应用于模型,但在这种情况下,所有其他装饰器都将失效,因此在并发应用程序中不应该经常发生。

【讨论】:

是的,这就是我要找的!谢谢...在实现这一点时,我肯定面临一些技术挑战——但我认为这完全是一个单独的问题。但是,命令模式与我正在尝试做的事情几乎完美匹配。

以上是关于为向量中的所有对象动态调用 C++ 类成员的主要内容,如果未能解决你的问题,请参考以下文章

Java中的动态反射机制和动态代理

动态调用成员方法c++

C++中的派生类,可以不定义对象直接调用基类的成员和调用自己的成员函数嘛???

对C++静态绑定与动态绑定的理解

调用 C++ 向量的每个元素的成员函数

c++类中 各种成员的生命周期?