Circular Dependency with Pimpls

Started by
19 comments, last by kunos 9 years, 11 months ago

Rather than just crowbarring it with a void, something you can do is:


class PhysicsBody
{
public:
    ~virtual PhysicsBody(){ }
};

// inside the Bullet specific Body

class BulletPhysicsBody : public PhysicsBody
{
public:
    btRigidBody *getBulletBody() const;
};

// inside the Bullet specific World

void handleBody(PhysicsBody *body)
{
#ifdef DEBUG
    BulletPhysicsBody *b = dynamic_cast<BulletPhysicsBody*>(body);
    if(!b) throw SomeKindOfAssertException();
#else
    BulletPhysicsBody *b = static_cast<BulletPhysicsBody*>(body);
#endif
    b->getBulletBody();
}

Static cast is pretty much free, but this gives you the option to check the cast in a debug build for example.

Just a thought. Creates even more interfaces to maintain of course :)

Advertisement

Rather than just crowbarring it with a void, something you can do is:


class PhysicsBody
{
public:
    ~virtual PhysicsBody(){ }
};

// inside the Bullet specific Body

class BulletPhysicsBody : public PhysicsBody
{
public:
    btRigidBody *getBulletBody() const;
};

// inside the Bullet specific World

void handleBody(PhysicsBody *body)
{
#ifdef DEBUG
    BulletPhysicsBody *b = dynamic_cast<BulletPhysicsBody*>(body);
    if(!b) throw SomeKindOfAssertException();
#else
    BulletPhysicsBody *b = static_cast<BulletPhysicsBody*>(body);
#endif
    b->getBulletBody();
}

Static cast is pretty much free, but this gives you the option to check the cast in a debug build for example.

Just a thought. Creates even more interfaces to maintain of course smile.png

Well, that's what I want to avoid. I don't want "Bullet" in the interface.

It could be a good solution, but personally I feel it is easier to change the implementation if the interface is consistent.


Well, that's what I want to avoid. I don't want "Bullet" in the interface.
It could be a good solution, but personally I feel it is easier to change the implementation if the interface is consistent.

You're missing my point. The "Bullet" stuff would only be inside the Bullet implementation of your interface. PhysicsBody is the only class the API would expose to the rest of the program.


Well, that's what I want to avoid. I don't want "Bullet" in the interface.
It could be a good solution, but personally I feel it is easier to change the implementation if the interface is consistent.

You're missing my point. The "Bullet" stuff would only be inside the Bullet implementation of your interface. PhysicsBody is the only class the API would expose to the rest of the program.

Wait, but I don't see how I can avoid calling "BulletRigidBody" constructor in the client code?

The BulletRigidBody would be inherited from RigidBody, so if I want to cast it to one, I'd need to create the derived class.

Further explanation would be nice.

Your PhysicsWorld interface should create the RigidBody instances via a virtual method. Then the Bullet implementation of PhysicsWorld privately creates BulletRigidBody instances and returns them as RigidBody pointers.

BulletPhysicsWorld can later privately retrieve BulletRigidBody from a RigidBody using a static or dynamic cast.

Well, it seems like this would become a huge mess.

I'll stick with void pointers for now, and see what happens.

Thanks for your posts however.

Edit:

Lol, just because I said I will see how it goes with void pointers, I get downvoted?

I mean, I get that they're hated, but seriously?

The way I do it, and they way I think most people abstract API is through either a pure abstract base class.. ie:

class IPhysicsEngine

{

public:

virtual IRigidBody* createRigidBody()=0;

// and so on

};

class IRigidBody

{

public:

virtual void addForce(blabla)=0;

// And so on

};

This is all that is visible to the client code, the application never knows what's behind those pure interfaces.

While the concrete (either in a DLL or in a static lib, or directly include in the project) implementation that looks like:

class BulletPhysicsEngine : public IPhysicsEngine

{

public:

IRigidBody* createRigidBody()

{

return new BulletRigidBody(this);

}

};

class BulletRigidBody : public IRigidBody

{

public:

void addForce(bla bla)

{

// Call bullet and do your stuff

}

};

Or through a C interface, for maximum "projectability" to different languages if that is a requirement.

Honestly, in 2014, seeing somebody thinking he has got a "solution" and that "solution" involves the use of a void* makes me want to puke some green yellow nasty stuff.

Stefano Casillo
TWITTER: [twitter]KunosStefano[/twitter]
AssettoCorsa - netKar PRO - Kunos Simulazioni

The way I do it, and they way I think most people abstract API is through either a pure abstract base class.. ie:

class IPhysicsEngine

{

public:

virtual IRigidBody* createRigidBody()=0;

// and so on

};

class IRigidBody

{

public:

virtual void addForce(blabla)=0;

// And so on

};

This is all that is visible to the client code, the application never knows what's behind those pure interfaces.

While the concrete (either in a DLL or in a static lib, or directly include in the project) implementation that looks like:

class BulletPhysicsEngine : public IPhysicsEngine

{

public:

IRigidBody* createRigidBody()

{

return new BulletRigidBody(this);

}

};

class BulletRigidBody : public IRigidBody

{

public:

void addForce(bla bla)

{

// Call bullet and do your stuff

}

};

Or through a C interface, for maximum "projectability" to different languages if that is a requirement.

Honestly, in 2014, seeing somebody thinking he has got a "solution" and that "solution" involves the use of a void* makes me want to puke some green yellow nasty stuff.

I do not see how I can avoid calling "BulletPhysicsEngine::createRigidBody()".

Could you please give an example of client code as well? Thanks.

Also, I did not say that void pointers was a "solution". I said I'll see how it goes. I haven't even continued with it yet, because I'm still thinking about it.

The client code will look something like this:

Somewhere you'll have to decide which concrete implementation to instantiate.. but that's going to be only one line in your code:

IPhysicsEngine* pengine=new BulletPhysicsEngine();

This is going to be the only API dependent call in the client code.. the rest is done through interface.. you have your IPhysicsEngine*, all your rigid bodies will be IRigidBody*:

IRigidBody* body=pengine->createRigidBody();

body->setMass(whateva);

body->addForce(whateva);

IRigidBody* body2=pengine->createRigidBody();

Similarly:

ISliderJoint* slider1=pengine->createSliderJoint();

slider1->attach(body,body2);

If one day you decide Bullet is not cutting it and you want to swap it over with something else.. you implement your concrete classes and change one line in the client code:

IPhysicsEngine* pengine=new HavokPhysicsEngine();

everything else stays the same.

Been there, done that.. it works, simple and clean.

Stefano Casillo
TWITTER: [twitter]KunosStefano[/twitter]
AssettoCorsa - netKar PRO - Kunos Simulazioni

The client code will look something like this:

Somewhere you'll have to decide which concrete implementation to instantiate.. but that's going to be only one line in your code:

IPhysicsEngine* pengine=new BulletPhysicsEngine();

This is going to be the only API dependent call in the client code.. the rest is done through interface.. you have your IPhysicsEngine*, all your rigid bodies will be IRigidBody*:

IRigidBody* body=pengine->createRigidBody();

body->setMass(whateva);

body->addForce(whateva);

IRigidBody* body2=pengine->createRigidBody();

Similarly:

ISliderJoint* slider1=pengine->createSliderJoint();

slider1->attach(body,body2);

If one day you decide Bullet is not cutting it and you want to swap it over with something else.. you implement your concrete classes and change one line in the client code:

IPhysicsEngine* pengine=new HavokPhysicsEngine();

everything else stays the same.

Been there, done that.. it works, simple and clean.

Oh, I didn't think about it like that. Sure, that actually seems like a pretty good solution.

+1'd you even though I'm a bit upset you -1'd me just because I didn't quite get the client side part, and that I mentioned I'd see how void pointers would go.

Either way, thanks again.

This topic is closed to new replies.

Advertisement