Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ convert base class pointer to derived class, without knowing derived class

I have various types of collider classes (SphereCollider, AABBCollider etc), all inheriting from the base class Collider. I store them using a pointer to the base class in a std::vector.

std::vector<std::shared_ptr<Collider>> colliders;

I then have various functions to work out whether the colliders are intersecting each other or not.

bool Colliding(const SphereCollider& colliderOne, const SphereCollider& colliderTwo);
bool Colliding(const AABBCollider& colliderOne, const AABBCollider& colliderTwo);
bool Colliding(const AABBCollider& colliderOne, const SphereCollider& colliderTwo);
bool Colliding(const SphereCollider& colliderOne, const AABBCollider& colliderTwo);

My idea was to simply iterate through the collider vector, and then compare each collider to the all the others in the list.

for (unsigned int a = 0; a < colliders.size(); ++a)
{
    for (unsigned int b = a + 1; b < colliders.size(); ++b)
    {
        // Store the two colliders we're current comparing
        std::shared_ptr<Collider> colliderOne = colliders[a];
        std::shared_ptr<Collider> colliderTwo = colliders[b];

        // Somehow cast pointers back to correct derived type

        // Check colliding
        if(Colliding(*colliderOneDerived, *colliderTwoDerived))
        {
            // Colliding
        }

    }
}

However to do this successfully, I would need to convert the pointers back to the correct derived type so that the correct function is called, but I do not know what type the collider will be each time.

The base collider class has a Type() function, which correctly returns the derived type from the base pointer.

std::type_index Collider::Type() { return typeid(*this); }

Is there a way I can use this to cast the pointer to the correct derived type?

like image 362
sangwe11 Avatar asked Oct 31 '22 09:10

sangwe11


1 Answers

What you want to do is called double dispatch which is not natively supported by C++. Here are a few options you might consider:

You could implement it with virtual functions which would mean adding virtual functions taking an object of every type to every object. This would result in a comparatively fast look up but the effort to implement it grows quadratically.

class Obj1;
class Obj2;

class Base{
    virtual bool collide(Base* p ) =0;
    virtual bool collide(Obj1*) = 0;
    virtual bool collide(Obj2*) = 0;
};

class Obj1{
    virtual bool collide(Base* p) override { return p->collide(this); }
    virtual bool collide(Obj1* p) override { return colliding(p,this); }
    virtual bool collide(Obj2* p) override;
};

class Obj2{
    virtual bool collide(Base* p) override { return p->collide(this); }
    virtual bool collide(Obj1* p) override { return colliding(p,this); }
    virtual bool collide(Obj2* p) override { return colliding(p,this); }
};

bool Obj1::collide(Obj2* p) override { return colliding(p,this); }

You could also use the Visitor pattern for much the same effect.

You could add one virtual function to each object returning the typeid of the object and make a sorted flat map of function pointers indexed by a pair of std::type_index. This would allow greater flexibility because you could add objects to the map in multiple places in your project.

You could add a unique constexpr index to each object, have a virtual function in each which returns this index and make a meta program which generates a look up table from a list of objects at compile time. This would be almost as fast as my fist example but would only require one virtual function per object and for all object types to be known at one point in the program. The user would be responsible for the uniqueness of the index but double indexes could be detected by the meta program reducing the change of error.

like image 198
odinthenerd Avatar answered Nov 09 '22 05:11

odinthenerd