C++ 如何创建多态容器
C++ How to create polymorphism container?
以下问题:我们有大网格。在每个点中,我们有两个具有不同结果数组的字段。
第一个数组是 3D。这意味着有三个坐标(i,j,k(,每个点都有五个物理数据(压力,密度,速度[x y z](。它看起来像:
Array3D < XXX::LocalFlow < double > > resultarray1;
LocalFlow 是一个自制的模板类,其中包含五个物理变量。
第二个数组是 4D。它被添加频率(i,j,k,f(。有很多频率。每个频率都有与平均流(第一个数组(相同的数据,但数据类型在这里complex <double>
。
Array4D < XXX::LocalFlow < std::complex < double > > > resultarray2;
我想合并这两个字段。
第一个想法:将第一个融入第二个。但这很糟糕,因为我需要数百万点的双倍内存空间(complex<double>
而不是double
(。
第二个想法:创建一个多态容器,其中包含具有不同数据类型的 LocalFlow 对象(第一个是双精度,其余所有复杂对象(。
我读了很多关于boost::any的信息。我的问题是:boost::any 是否仅适用于简单的类型,如 int、float、double 或自己的类型?
还有其他方法可以解决我的问题吗?
我会看看 boost 变体,因为您想要存储的类型没有太大不同 (2(。特别是对于访问者模式,这使得读取/写入/更改数据变得容易。
另一个解决方案是,据我所知,创建一个三维网格,其中元素如下所示:
struct type
{
XXX::LocalFlow < double > mean_element;
XXX::LocalFlow < std::complex<double> > * f_values_array;
}
矫枉过正,因为从本质上讲,boost::any 是使用通用类型的 void* 的"更安全"方式。
正如@ThomasFannes所建议的,boost::variant 是一个选项,因为它建议以一种优雅、非常易于阅读的方式执行静态多态性。
但是,为了多样化,我建议另一种选择。
首先,让我们定义一个GenericLocalFlow
结构,该结构将承载LocalFlow<double>
或LocalFlow<std::complex<double>>
,例如,使用 boost::optional
类。此泛型类存储的实际类型在构造时确定。此类的实现可以读取
class GenericLocalFlow {
// Here, you could define constructors that fit your needs...
// ...
boost::optional<LocalFlow<double>>& asScalar();
boost::optional<LocalFlow<std::complex<double>>>& asComplex();
};
请注意,成员函数不const
用于读/写目的。此外,在调用任一成员函数时,您可以查询结构的标量版本或复杂版本是否已初始化。
然后,我建议您将完整的数据集存储在
Array3D<std::vector<GenericLocalFlow>> results;
std::矢量占第四维,即频率。
我直言,最好的两种可能性是:
- 创建自定义向量,该向量
- 将分别保存每种类型,并在引擎盖下有两个单独的向量。
- 为两者创建基类,并通过虚拟类使用(运行时(多态性。然后,您当然不需要直接存储对象,而是指向它们的指针(但是,每个值都需要额外的两个指针,这可能很容易大于额外的双精度的大小,并且实际上还需要这两个指针对于复杂<>类型(。
boost::any 与解决方案 2 基本相同。 - 它在后台使用类型擦除,因此每个实例也有两个额外的指针(指向类型擦除持有者的指针和指向其虚拟表的指针(。有了"奖励",您将需要将所有内容来回键入正确的类型。
使用 boost::variant 你没有额外的虚拟指针,但不幸的是,boost::variant 存储必须(显然(与它可以容纳的最大类型一样大(所以直接合并类型没有改进,关于内存使用情况(。
请参阅我对类似问题的回答:https://stackoverflow.com/a/35003245/1274747
上面的选项 1. 还有一个优点,那就是您可以分别迭代不同的类型,这对于 CPU 缓存行为更好(对于具有虚拟方法的多态类尤其如此,这就是为什么游戏程序员有时会根据实际类型对多态游戏对象的集合进行排序,以迭代块中的各种类型,从而不会丢弃指令缓存 - 所以即使在情况 2.可能希望根据不同的类型对它们进行排序(。
不要这样做。 只需存储复数数组。
如果 f 大小中等(例如 50-100(,则在较小维度上将 1 个数组的大小剃掉一倍可节省 0.5% 的内存。
元素上的任何类型的安全变体都将使用比这更多的方法。 我们谈论的是 20%-100% 的内存开销和可能严重的运行时成本。
一个三维double, array<complex<double>>
数组,其中第一个是"f=0
",数组是频率数据确实减少了0.5%(好吧,频率计数/200(,代价是代码复杂性和访问速度较慢(由于分支(。
除非频率数量很少,或者您更频繁地访问 f=0 数据数量级(因此缓存命中率使用紧凑数据更好(,或者您除了微小的优化之外没有什么更好的事情要做,否则您的计划看起来不是一个好主意。
- 多态性和功能结合
- 具有默认模板参数的多态类的模板推导失败
- 找不到成员对象:没有名为get_event()的成员,也处理多态性和向量
- 在 C++ 中在堆栈上创建实例时如何保持多态性?
- 创建基类指针的向量并将派生类对象传递给它(多态性)
- C++结合静态和动态多态性来创建"Hyper Polymorphism"?
- 如果在编译时间中创建虚拟表,那么为什么我们将其称为运行时间多态性
- 如何多态地创建对象的动态数组
- 为什么不能在不创建实例的情况下使用多态类
- 在C++中创建一个具有多态性和操作重载的模板
- 如何在堆栈上创建多态对象
- C++ 如何创建多态容器
- 如何在具有多态性的函数外部创建对象
- 在堆上创建多态对象的数据成员向量
- 有没有可能创建一个数组,在初始化时我们不知道元素的数量?(处理遗传/多态性)
- 使用多态性创建"类型数组"
- 如何在C++中创建一个工厂方法,允许以多态方式返回不同的类型
- 如何在c++中创建一个多态和可添加的init()函数
- 基类的shared_pointer不能使用多态派生创建
- 如何从指向多态基类的指针复制/创建派生类实例