如何解决这个 C++ 多重继承类似的问题

Posted

技术标签:

【中文标题】如何解决这个 C++ 多重继承类似的问题【英文标题】:How to solve this C++ multiple inheritance similar issue 【发布时间】:2014-11-27 18:10:05 【问题描述】:

我想知道避免以下问题的推荐方法是什么。

我有一个rigidBody3D 类,它有一个指向另一个rigidBody 结构的指针,还有一个继承了rigidBody3D 的box3D 类。

class rigidBody3D 
public:
    void setPosition(float x, float y, float z);
    rigidBody* rb;
;

class box3D : public rigidBody3D 
public:
    box3D(float w float h, float l);
    ..other box functions..
;

然后我有使用这些 3D 类的 2D 类。

class rigidBody2D 
public:
    rigidBody2D();
    void setPosition(float x, float y);
    rigidBody3D body;
;

class box2D : public rigidBody2D 
public:
    box2D(float w, float h);
    box3D box;
;

例如rigidBody2D的setPosition调用它的rigidBody3D的3D setPosition。

void rigidBody2D::setPosition(float x, float y)

    body.setPosition(x,y,0);

问题:

照原样,创建一个 box2D 对象会创建两个刚体指针。一个是因为 box2D 继承了具有rigidBody3D 的rigidBody2D。另一个是因为 box2D 有一个 box3D 对象,它继承了rigidBody3D。

我只想要一个刚体指针。我还希望能够为 box2D 等 2D 类调用 2D setPosition,但也可以调用它们的 3D 特定函数,例如 box2D 调用 box3D。

解决方案:

我使用虚拟继承来解决这个问题,并且继承了 3D 类而不是拥有它们的对象。

class rigidBody3D 
public:
    void setPosition(float x, float y, float z);
    rigidBody* rb;
;

class box3D : public virtual rigidBody3D 
public:
    box3D(float w float h, float l);
    ..other box functions..
;

class rigidBody2D : private virtual rigidBody3D 
public:
    rigidBody2D();
    void setPosition(float x, float y);
;

class box2D : public rigidBody2D, private box3D  
public:
    box2D(float w, float h);
;

void rigidBody2D::setPosition(float x, float y)

    rigidBody3D::setPosition(x,y,0);

【问题讨论】:

你想通过让 2d 身体保持 3d 身体来实现什么?你想模拟什么样的真实世界情况? 为什么不从3D物体继承2D物体,并将z坐标设置为0呢?您可能还应该更多地考虑您的设计,以及基类中应该包含什么。 我有一个指针指向的原始刚体的界面全是 3D。我想让我的 3D 图层尽可能靠近指针。我的 2D 类是为了简化我以后添加 2D 对象的任务,这些对象是以 2D 绘制的 3D 对象,并且它们的 z 分量设置为 0。 重新设计是我想做的。知道我想要一个 3D 后端和一个简化的 2D 界面,您有什么建议吗? 这是一种可能的解决方案。另一种方法是将层次结构模板化为维度数量,以便您拥有object<2>object<3> 等。 【参考方案1】:

您的评论:

我想要 (...) 2D 对象,它们是 3D 对象,以 2D 形式绘制并具有其 z 组件设置为 0

强烈建议rigidBody2D 是一个 rigidBody3D,而box2D 是一个强>box3D。因此,更喜欢继承而不是组合似乎很自然:

替代方案 1:简单继承

这里我们将考虑所有这些 2D 和 3D 对象的根是rigidBody2D。 一个问题仍然存在: box2D 更像是一种 box3D 还是更像是一种 rididBody2D ?

class rigidBody2D : public rigidBody3D 
public:
    rigidBody2D();
    void setPosition(float x, float y);
    // no body anymore:  it's inherited from rigidBody3D 
;
class box2D : public box3D   // is it more like a box3d or more like a rigiBbody2D ? You decide ! 
public:
    box2D(float w, float h);
    // no box anymore:  it's inherited from box3D 
;
box2D::box2D (float w, float h) : box3D (w, h, 0)  /*...*/   // how to create a box2D as a special case of box3D

void rigidBody2D::setPosition(float x, float y)  // call the setpos of the parent.  

    rigidBody3D::setPosition(x, y, 0);  // call parent's setpos

所有其他对象都从rigidBody3D 继承,然后有一个指向rigidBody 的指针。

实际上,另一个问题是要知道rigidBody3D 自己是否不应该从rigidBody 继承,或者是否有强烈的反对意见(例如:如果两者的寿命不同)。

备选方案 2:多重继承

这里是关于box2D的设计。它是否更像一个 box3D,具有相同类型的成员函数,但比 box3D,但考虑到第三维是 0 ?或者它更像是一个rigidBody2D,因为它应该拥有并使用这个对象提供的所有成员函数?

如果您可以轻松决定,请返回备选方案 1。

如果你不能决定,因为它有点两者兼而有之,那么你可以考虑多重继承:

class box2D : public box3D, public rigidBody2D    
public:
    box2D(float w, float h);
    // no box anymore:  it's inherited from box3D 
;

那么您将继承成员(两者的函数和数据)。然而多重继承并不容易。您将在这里有 2 个刚体指针:从盒子继承的指针和从主体继承的指针。

在您的情况下,可以通过将rigidBody3D 虚拟继承来解决此问题:

class rigidBody2D : public virtual rigidBody3D  ... ;
class box3D : public virtual rigidBody3D  ... ;

在这种情况下,如果一个对象继承了多次rigidBody3D,那么只会创建一个这样的子对象。

【讨论】:

非常感谢!我实际上使用了它们的组合。【参考方案2】:

在我看来,2d 和 3d 对象的相关性仅在于它们是根据刚体* 实现的。 setPosition 的语义对于这两个概念是不同的。

另一种说法是,2d body 不是 一种 3d body,它是一个不同的概念,所以它们之间似乎不应该有继承关系。

所以我会从这些思路开始:

struct rigid_body_3d_concept 
  virtual ~rigid_body_3d_concept();
  void set_position(double x, double y, double z) 
    _impl->really_set_the_position(x, y, z);
  
private:
  rigidbody* _impl;
;

struct rigid_body_2d_concept 
  virtual ~rigid_body_2d_concept();
  void set_position(double x, double y) 
    _impl->really_set_the_position(x, y, 0);
  
private:
  rigidbody* _impl;
;

struct box3d 
: public rigid_body_3d_concept 

    box3d(double w, double h, double l);
;

struct box2d 
: public rigid_body_2d_concept 

    box2d(double w, double h);
;

【讨论】:

以上是关于如何解决这个 C++ 多重继承类似的问题的主要内容,如果未能解决你的问题,请参考以下文章

c++多重继承及优缺点

c++多重继承及优缺点

C++中的多重继承

C# 应该有多重继承吗? [关闭]

c++ 多重继承强制转换

继承受保护函数和公共变量 C++ 的多重继承编译错误