派生 class of b2Body 或 class 包含 b2Body 对象?
Derived class of b2Body or class containing a b2Body object?
我目前有一个 class 'WorldObject',其中包含一个指向其 b2Body 的指针,以及几个方法和变量。
但是让 WorldObject 成为 b2Body 的派生 class 不是更聪明吗?
处理这类事情的一般方法是什么?要始终创建 class 中最重要对象的派生 class,还是只创建一个新对象并使所有内容都具有属性?
这些可能性的优缺点是什么?
谢谢。
没有最好的办法。这完全取决于上下文:
有一个指向 b2Body
的指针实现了一个组合关系,即 WorldObject
有一个 b2Body
。
使 WorldObject
派生自 b2Body
实现继承,并且仅当 WorldObject
是 b2Body
时才执行。这意味着原则上你可以用 WorldObject
object 做任何你可以用 b2Boby
做的事情(甚至更多)。
经验法则是 preferring composition over inheritance。除非你真的有明显的遗传。
在你的例子中,b2Body
是刚性的 body。现在问你一个问题:你的 object 是 body 吗?或者你的 object 有 body 吗?
更实用:这种设计的优点是将Box2D引擎的选择封装在你的WorldObject
中。如果稍后您使用另一个 API 将您的软件移植到另一个物理引擎,这可以让您更好地控制影响。如果您改为使用继承,底层引擎 API 将显着影响您自己软件的设计,并且有一天很难迁移到另一个引擎。
通常最好进行组合而不是过度使用继承。
另请注意,您通常会创建一个调用 b2World::CreateBody()
和 returns 一个 b2Body*
的正文,并且继承是不可能的。
为了避免内部 b2Body*
的生命周期问题,您可以使用智能指针。我使用这个定义:
class BodyDeleter
{
public:
BodyDeleter()
:m_world(NULL)
{}
BodyDeleter(b2World *world)
:m_world(world)
{}
void operator()(b2Body *body)
{
if (m_world)
m_world->DestroyBody(body);
}
private:
b2World *m_world;
};
typedef std::unique_ptr<b2Body, BodyDeleter> b2BodyPtr;
然后,在我的 WorldObject
:
class WorldObject
{
protected:
WorldObject(b2World *world)
:m_body(NULL, m_world)
{}
b2BodyPtr m_body;
};
然后,在WorldObject
的实际子类中:
class SpaceShip : public WorldObject
{
public:
SpaceShip(b2World *world)
:WorldObject(world)
{
//initialize bodydef and whatever
m_body.reset(world->CreateBody(...));
}
};
您一定更喜欢组合而不是继承。组成避免fragile base class problem.
与方法调用不同,继承违反了封装
Subclasses 依赖于它们的 superclasses,它可以被改变,因此 subclasses
中的功能被破坏
使用组合和转发而不是继承,特别是如果存在实现包装器的适当接口 class。
当class设计为继承时使用继承
我建议您阅读 Joshua bloch 的 "Effective Java" 一书的第 16 "favor composition over inheritance" 条
我目前有一个 class 'WorldObject',其中包含一个指向其 b2Body 的指针,以及几个方法和变量。
但是让 WorldObject 成为 b2Body 的派生 class 不是更聪明吗?
处理这类事情的一般方法是什么?要始终创建 class 中最重要对象的派生 class,还是只创建一个新对象并使所有内容都具有属性?
这些可能性的优缺点是什么?
谢谢。
没有最好的办法。这完全取决于上下文:
有一个指向
b2Body
的指针实现了一个组合关系,即WorldObject
有一个b2Body
。使
WorldObject
派生自b2Body
实现继承,并且仅当WorldObject
是b2Body
时才执行。这意味着原则上你可以用WorldObject
object 做任何你可以用b2Boby
做的事情(甚至更多)。
经验法则是 preferring composition over inheritance。除非你真的有明显的遗传。
在你的例子中,b2Body
是刚性的 body。现在问你一个问题:你的 object 是 body 吗?或者你的 object 有 body 吗?
更实用:这种设计的优点是将Box2D引擎的选择封装在你的WorldObject
中。如果稍后您使用另一个 API 将您的软件移植到另一个物理引擎,这可以让您更好地控制影响。如果您改为使用继承,底层引擎 API 将显着影响您自己软件的设计,并且有一天很难迁移到另一个引擎。
通常最好进行组合而不是过度使用继承。
另请注意,您通常会创建一个调用 b2World::CreateBody()
和 returns 一个 b2Body*
的正文,并且继承是不可能的。
为了避免内部 b2Body*
的生命周期问题,您可以使用智能指针。我使用这个定义:
class BodyDeleter
{
public:
BodyDeleter()
:m_world(NULL)
{}
BodyDeleter(b2World *world)
:m_world(world)
{}
void operator()(b2Body *body)
{
if (m_world)
m_world->DestroyBody(body);
}
private:
b2World *m_world;
};
typedef std::unique_ptr<b2Body, BodyDeleter> b2BodyPtr;
然后,在我的 WorldObject
:
class WorldObject
{
protected:
WorldObject(b2World *world)
:m_body(NULL, m_world)
{}
b2BodyPtr m_body;
};
然后,在WorldObject
的实际子类中:
class SpaceShip : public WorldObject
{
public:
SpaceShip(b2World *world)
:WorldObject(world)
{
//initialize bodydef and whatever
m_body.reset(world->CreateBody(...));
}
};
您一定更喜欢组合而不是继承。组成避免fragile base class problem.
与方法调用不同,继承违反了封装
Subclasses 依赖于它们的 superclasses,它可以被改变,因此 subclasses
中的功能被破坏使用组合和转发而不是继承,特别是如果存在实现包装器的适当接口 class。
当class设计为继承时使用继承
我建议您阅读 Joshua bloch 的 "Effective Java" 一书的第 16 "favor composition over inheritance" 条