C++ issue concerning inheritance and casting
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;
B开发者_Python百科ut 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 RigidBody
and its derived classes:
bool isCollidingWith(RigidBody* rb_p) = 0;
In the derived classes, e.g. Sphere
, the implementation would look like:
bool Sphere::isCollidingWith(RigidBody* rb_p)
{
return rb_p->isCollidingWith(this);
}
This works because the first time isCollidingWith
is called (in your loop), the version of isCollidingWith(RigidBody*)
from the correct derived class is called (via the virtual method). Then, in Sphere::isCollidingWith(RigidBody*)
, the correct derived class is used via the virtual method. However, this time, this
is a Sphere*
, so the overload that is called is the isCollidingWith(Sphere*)
version.
In other words:
In your loop:
this->bodies_p[i]->isCollidingWith(this->bodies_p[j])
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)
:return rb_p->isCollidingWith(this);
which calls either
Sphere::isCollidingWith(Sphere*)
orCustomRigidBody::isCollidingWith(Sphere*)
, depending on the actual type ofrb_p
.
精彩评论