具有共享遗传的C++多态性

Polymorphism in C++ with shared inheritance

本文关键字:C++ 多态性 共享      更新时间:2023-10-16

我正在考虑实现GIS中使用的一套点类型,它们是2D(xy)、3D(xyz或xym)或4D(xyzm)。M坐标是度量坐标,其他坐标应该是明显的。然而,我似乎不知道如何使PointZM类共享Point类的xy成员。这是我的代码:

#include <iostream>
class Point {
  public:
    double x, y;
    Point (double xNew, double yNew) : x(xNew), y(yNew) {};
};
class PointZ : public Point {
  public:
    double z;
    PointZ (double xNew, double yNew, double zNew) :
        Point(xNew, yNew), z(zNew) {};
};
class PointM : public Point {
  public:
    double m;
    PointM (double xNew, double yNew, double mNew) :
        Point(xNew, yNew), m(mNew) {};
};
class PointZM : public PointZ, public PointM {
  public:
      PointZM (double xNew, double yNew, double zNew, double mNew) :
          PointZ(xNew, yNew, zNew), PointM(xNew, yNew, mNew) {};
};
int main () {
    Point p (1, 2);
    PointZ pZ (1, 2, 3);
    PointM pM (1, 2, 4);
    PointZM pZM (1, 2, 3, 4);
    std::cout << "Point: " << sizeof(p) << std::endl;
    std::cout << "PointZ: " << sizeof(pZ) << std::endl;
    std::cout << "PointM: " << sizeof(pM) << std::endl;
    std::cout << "PointZM: " << sizeof(pZM) << std::endl;
}

打印每个类的四个实例的大小:

Point: 16
PointZ: 24
PointM: 24
PointZM: 48

我希望最后一个PointZM是32字节,因为它应该有xyzm成员。如何让两个继承的类PointZPointM共享它们继承的Point成员?有什么办法使两个阶级联合起来吗?我是这个话题的C++新手。

为什么要麻烦继承的动机在简单的点几何中并不明显。然而,当进一步开发不同的几何类型时,如LineString(2D)、LineStringZ(3D)、LineStringM(3D)或LineStringZM(4D),它们将具有length方法,如果存在Z维度,则该方法将不同。只有当存在Z维度时,长度方法的计算才会有所不同,我不想加倍努力将其添加到LineStringZLineStringZM类中。

有2D几何、3D几何和4D几何。3D几何体不是2D几何体的精细实例,它是一个完全不同的野兽。同样,4D几何体不是3D几何体的特殊情况。

公共继承旨在表达is-a关系。不同尺寸的几何体之间没有这种关系。

非公共继承可以用于代码共享,但尚不清楚在2D、3D和4D情况下可以共享哪些代码。

然而,所有这些几何都是通用N维几何的情况,N是一个参数。用类模板对此进行建模是很自然的。

   template <size_t N>
   class Point
   {
      std::array<double, N> coord;
      // ... rest of the code ...
   };

问题的直接答案是使用虚拟继承。这将使PointZM只包含一个点,而不是两个。稍后您可能会认为这不值得这么复杂,而是单独实现PointZ、PointM和PointZM,但这取决于您。

在我的系统中,虚拟继承为每个虚拟派生类型添加了8个字节,PointZM保持相同的大小,因为它包含的额外Point的16个字节被删除了,但我们现在为虚拟基类存储了两个额外的指针。那么尺寸看起来是这样的:

Point: 16
PointZ: 32
PointM: 32
PointZM: 48