C++ 处理可以';你不能实例化自己吗?

C++ 处理可以';你不能实例化自己吗?,c++,design-patterns,qt,box2d,C++,Design Patterns,Qt,Box2d,我想我以前也问过一些类似的问题,但我是绕圈子的。我想这才是真正的问题,我不能完全放心 我处理的是一个,有一个对象无法创建自己,b2Body。b2World的。我个人不太喜欢这种设计模式;我认为,b2Body应该能够独立于世界而存在,然后在需要时添加到世界中。无论如何,我已经用我自己的类,Body包装了b2Body,因为我需要向它添加一些额外的东西。类似地,我有一个World包装器。现在我想我有3个选择: HaveBody的构造函数获取指向World的指针,这样它就可以被完全实例化(调用b2Wor

我想我以前也问过一些类似的问题,但我是绕圈子的。我想这才是真正的问题,我不能完全放心

我处理的是一个,有一个对象无法创建自己,
b2Body
。b2World的
。我个人不太喜欢这种设计模式;我认为,
b2Body
应该能够独立于世界而存在,然后在需要时添加到世界中。无论如何,我已经用我自己的类,
Body
包装了
b2Body
,因为我需要向它添加一些额外的东西。类似地,我有一个
World
包装器。现在我想我有3个选择:

  • Have
    Body
    的构造函数获取指向
    World
    的指针,这样它就可以被完全实例化(调用
    b2World::CreateBody
    内部的某个地方)——也就是说,有一个像
    Body*b=newbody(World_ptr)
  • Body
    传递给一些
    World::CreateBody
    方法,就像库已经做过的那样——即
    Body*b=World.CreateBody(params)
  • 复制
    b2Body
    中的所有数据,以便您可以随意使用它,然后在您将其添加到世界后,它将“切换”到使用
    b2Body
    数据,即
    Body b
    和以后的
    world.addBody(b)
  • (1) (2)意味着如果没有一个
    世界,你就不能拥有
    主体
    ,我可能不需要它,但拥有这个选项可能会更好[这样我就可以将它用作其他对象等的模板]。不知道还有什么其他的优点和缺点。(3) 看起来更好,但要实现它需要做更多的工作,这意味着我必须复制
    b2Body
    中已经包含的大部分数据

    你的想法是什么?我将
    CW
    这样就不会有人担心了


    我还是不能就此罢休。这是每个选项的外观:

    选项1:(我更喜欢)

    选项2:(中间的某个地方)

    选项3:(Box2D是如何实现的)

    选项2和3没有什么不同,但它改变了谁可以控制对象的创建


    但是,我将如何实际实施选项3
    World::CreateBody()
    必须调用
    b2World::CreateBody(args)
    它调用
    b2Body::b2Body()
    并返回
    b2Body
    ,但从不调用
    Body::Body(args)
    ,这是一个问题。
    b2Body
    将被完全初始化,但我的包装器没有地方做它的事情。。。更具体地说,我将如何编写
    World::CreateBody(constbodydef&bd)
    ?假设BodyDef继承自b2BodyDef、b2Body继承自b2Body、b2World继承自b2World等等。

    听起来b2World对象是b2Body的工厂,因此作者认为b2Body没有世界就没有意义

    我的第一反应是,这是接口,所以请接受它。让你的世界对象成为你身体的工厂。这接近方法(1),除了没有公共构造函数外,世界对象有一个makeBody()方法

    你认为没有世界的身体有意义吗?如果是这样的话,也许你会发现身体方法的某些子集在没有世界的情况下是有用的,我不清楚你是如何实现它们的——它们显然不能由b2Body实现,因为没有b2Body他就不可能存在。因此,一种可能性是您有一组配置信息

     class Body {
            int howBig;
            String name;
            Flavour flavour;
            // and getter/setters
     } 
    
    现在这些(或在东方的bgetters)显然在有或没有世界的情况下都是有意义的

    考虑到这一点,我想你们可能会发现,你们的身体实际上有两种“状态”,一种是和世界无关的状态,另一种是和世界相关的状态。而实际能力是不同的。因此,实际上有两个接口

    所以有一个独立的Body类和一个Body类。世界工厂方法可能有一个签名

    World {
    
        Body makeBody(IndependentBody);
    
    }
    

    我认为,如果你打算使用第三方库,你应该只有在你有更好的理由的情况下才反对它的设计,而不是哦,我不太喜欢那种设计模式。您的库有一种处理事情的方式—显然,通过使用工厂对象—并与之抗争,这将增加您的代码复杂性,可能会大大增加。

    我同意您不应该与正在使用的第三方库的设计抗争。沿着这条路走下去会在未来造成很多问题

    通过查看“隐藏”和创建包装,您可能将第三方库的行为锁定为当前实现的行为方式

    如果API的未来版本保持不变,但底层语义发生变化,会发生什么情况

    突然间,从包装纸的角度来看,一切都被打破了


    仅我的0.02。

    在您的链接之后,我看到
    createBody
    不返回b2Body,而是指向b2Body的指针:

    这很可能是因为这个世界

  • 管理b2Body生存期(即,当B2World超出范围/自身被删除时,删除它和它使用的内存),或

  • 因为B2WSWorld需要维护指向B2Body的指针,例如,对它们进行迭代以实现某些B2World功能

  • 我还注意到创建
    b2Body
    所需的全部(除了
    b2World
    )是指向
    b2BodyDef
    的指针

    所以,如果你想要一个b2Body,它没有连接到一个b2World,但是可以在以后连接到一个b2Body,为什么不传递b2BodyDefs,或者指向它们的指针呢

    我可能会为b2BodyDef创建一个薄包装,例如:

    请注意,我可以将此b2BodyDefWrapper附加到多个世界,或者多次附加到同一个世界

    现在,您可能可以对b2BodyDef执行您无法对b2BodyDef执行的操作,因此传递(可能包装)b2BodyDefs w
    World *w = new World;
    Body *b = w->CreateBody(args);
    Fixture *f = b->CreateFixture(args);
    
     class Body {
            int howBig;
            String name;
            Flavour flavour;
            // and getter/setters
     } 
    
    World {
    
        Body makeBody(IndependentBody);
    
    }
    
     b2Body* b2World::CreateBody  ( const b2BodyDef*  def );     
    
     class b2BodyDefWrapper {
       public const b2BodyDef& b2bodyDef;
       public b2BodyDefWrapper( const b2BodyDef& bodydef ) : b2bodyDef(bodydef) {}
       public const b2Body* reifyOn( b2World& world) const { 
         return world.CreateBody( b2bodyDef ) ;
       }
     }
    
     class b2BodyDefWrapper {
       private std::vector<Command&> commandStack;
       public const b2BodyDef& b2bodyDef;
       public b2BodyDefWrapper( const b2BodyDef& bodydef ) : b2bodyDef(bodydef) {}
       public const b2Body* reify( b2World& world) const { 
         b2body* ret = world.CreateBody( &b2bodyDef ) ;
         for (int i=0; i< commandStack.size(); i++) {
            v[i].applyTo( ret ) ;
         }
         return ret;
       }
    
       public void addCommand( const Command& command ) {
          commandStack.push_back( command );
       }
     }
    
      class Command {
         virtual ~Command() {}
         virtual void applyTo( b2Body* body ) = 0 ;
      }
    
     class ApplyForce : public Command {
       private const b2Vec2& force;
       private const b2Vec2& point;
       ApplyForce(const b2Vec2& f, const b2Vec2& p) : force(f), point(p) {}
       virtual void applyTo( b2Body* body ) {
          body->ApplyForce( force, point ) ;
       }
     }
    
    extern b2BodyDef& makeb2BodyDef();
    b2BodyDefWrapper w( makeb2BodyDef()  ) ; 
    ApplyForce a( ..., ... );
    w.addCommand( a ) ;
    ...
    b2World myworld;
    b2World hisWorld;
    w.reifyOn( myWorld ) ;
    w.reifyOn( hisWorld) ;
    
    b2BodyDef myDef;
    // fill out def
    
    for (int i=0; i < 100; ++i) {
       for (int j=0; j < 100; ++j) {
          myDef.x = i;
          myDef.y = j
          b2Body* body = world.CreateBody(myDef)
       }
    }