简体   繁体   English

C ++中的多态性与共享继承

[英]Polymorphism in C++ with shared inheritance

I'm looking at implementing a suite of point types used in GIS, which are either 2D (xy), 3D (xyz or xym) or 4D (xyzm). 我正在研究实现GIS中使用的一套点类型,它们是2D(xy),3D(xyz或xym)或4D(xyzm)。 The M-coordinate is a measure coordinate, and the others should be obvious. M坐标是度量坐标,其他坐标应该是显而易见的。 However, I can't seem to figure out how to make the PointZM class share the x and y members from the Point class. 但是,我似乎无法弄清楚如何使PointZM类从Point类共享xy成员。 Here is my code: 这是我的代码:

#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;
}

Prints the size of the four instances of each class: 打印每个类的四个实例的大小:

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

I was expecting the last PointZM to be 32 bytes, as it should have x , y , z and m members. 我期待最后一个PointZM是32个字节,因为它应该有xyzm成员。 How can I get the two inherited classes PointZ and PointM to share their inherited Point members? 我怎样才能获得两个继承的类PointZPointM分享他们所继承的Point的成员? Is the some way to get the union of two classes? 有两种方法可以获得两个类的联合吗? I'm a C++ novice with this topic. 我是这个主题的C ++新手。

The motivation on why to bother with inheritance is not apparent with simple point geometries. 简单的点几何形状对于为什么要对继承感到困扰的动机并不明显。 However, when further developing different geometry types, like LineString (2D), LineStringZ (3D), LineStringM (3D) or LineStringZM (4D), they would have a length method which would be different if there was a Z-dimension. 但是,当进一步开发不同的几何类型(如LineString (2D), LineStringZ (3D), LineStringM (3D)或LineStringZM (4D))时,如果存在Z维,它们将具有不同的length方法。 The length method would be calculated differently only if there is a Z-dimension, and I wouldn't want to double the efforts to add this to LineStringZ and LineStringZM classes. 只有存在Z维度时,长度方法才会有不同的计算方式,我不想加倍努力将其添加到LineStringZLineStringZM类。

There is 2D geometry, 3D geometry and 4D geometry. 有2D几何,3D几何和4D几何。 3D geometry is not a refined instance of 2D geometry, it is a totally different beast. 3D几何体不是2D几何体的精细实例,它是一种完全不同的野兽。 Likewise 4D geometry is not a special case of 3D geometry. 同样,4D几何不是3D几何的特殊情况。

Public inheritance is intended to express the is-a relationship. 公共继承旨在表达is-a关系。 There's no such relationship between differently dimensioned geometries. 不同尺寸的几何形状之间没有这种关系。

Non-public inheritance can be used for code sharing, but it is not clear what code can be shared between 2D, 3D and 4D cases. 非公共继承可用于代码共享,但不清楚在2D,3D和4D情况下可以共享哪些代码。

However, all of those geometries are cases of generic N-dimensioned geometry , N being a parameter. 但是,所有这些几何都是通用N维几何的情况 ,N是参数。 It would be natural to model this with a class template. 用类模板对它进行建模是很自然的。

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

The direct answer to your question is to use virtual inheritance . 您问题的直接答案是使用虚拟继承 This would make PointZM contain just one Point, rather than two. 这将使PointZM只包含一个Point,而不是两个。 You might later decide this isn't worth the complexity, and instead just implement PointZ, PointM, and PointZM separately, but that's up to you. 您可能稍后会认为这不值得复杂,而只是分别实现PointZ,PointM和PointZM,但这取决于您。

On my system, virtual inheritance adds 8 bytes to each virtually-derived type, and PointZM stays the same size because the 16 bytes of the extra Point it contained are removed but we now have two extra pointers stored for the virtual base classes. 在我的系统上,虚拟继承为每个虚拟派生类型增加了8个字节,并且PointZM保持相同的大小,因为它包含的额外Point的16个字节被删除,但我们现在为虚拟基类存储了两个额外的指针。 So then the sizes look like this: 那么尺寸看起来像这样:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM