I am currently working on an amateur physic engine for a school project but I’m stuck because of a C++ issue. The setting is the following :
I have three different classes :
- RigidBody (abstract)
- Sphere (inherits from RigidBody)
- CustomRigidBody (inherits from RigidBody and represents a polyhedra)
I need to check if a collision occurs between a pair of bodies with two eponymous methods. One is used to check for a contact with a Sphere whereas the other is used to check for a contact with a CustomRigidBody. There are several possible scenarii (Sphere/Sphere collision, Sphere/Custom collision, etc…) so these two methods are defined within all of these classes.
In RigidBody, they are abstract :
virtual bool isCollidingWith(Sphere* s_p) = 0;
virtual bool isCollidingWith(CustomRigidBody* rb_p) = 0;
But not in Sphere :
bool isCollidingWith(Sphere* s_p);
bool isCollidingWith(CustomRigidBody* rb_p);
Nor in CustomRigidBody :
bool isCollidingWith(Sphere* s_p);
bool isCollidingWith(CustomRigidBody* rb_p);
In my main program, I have a std::vector<RigidBody*> containing pointers to RigidBodies (the superclass) and I need to check for collisions between objects by pair by calling something like :
for(int i = 1; i < this->bodies_p.size(); ++i)
for(int j = 0; j < i; ++j)
if(this->bodies_p[i]->isCollidingWith(this->bodies_p[j]))
std::cout << " COLLISION BETWEEN " << i << " AND " << j << std::endl;
I was under the impression that C++ would be OK with that but I get the following error message :
Engine.cc:35: error: no matching function for call to ‘RigidBody::isCollidingWith(RigidBody*&)’
RigidBody.h:53: note: candidates are: virtual bool RigidBody::isCollidingWith(Sphere*)
RigidBody.h:54: note: virtual bool RigidBody::isCollidingWith(CustomRigidBody*)
My guess is that it has to do with the fact that the vector of bodies contains pointers to RigidBodies and they are not automatically casted to Sphere* or CustomRigidBody* but I don’t know how to fix the issue.
Thank you for your assistance 😉
This problem is solved by Double Dispatch. Essentially, you need to add another overload to
RigidBodyand its derived classes:In the derived classes, e.g.
Sphere, the implementation would look like:This works because the first time
isCollidingWithis called (in your loop), the version ofisCollidingWith(RigidBody*)from the correct derived class is called (via the virtual method). Then, inSphere::isCollidingWith(RigidBody*), the correct derived class is used via the virtual method. However, this time,thisis aSphere*, so the overload that is called is theisCollidingWith(Sphere*)version.In other words:
In your loop:
will call either
Sphere::isCollidingWith(RigidBody*)orCustomRigidBody::isCollidingWith(RigidBody*), depending on the actual type ofbodies_p[i]. Assuming it is aSphere, then we getIn
Sphere::isCollidingWith(RigidBody* rb_p):which calls either
Sphere::isCollidingWith(Sphere*)orCustomRigidBody::isCollidingWith(Sphere*), depending on the actual type ofrb_p.