I am working on a bounding box/collision detection system and I am using different types of bounding volumes, id like all the bounding volumes to derive the same base class and then using pure virtual functions forcing all derived classes to implement basic functions like
isCollidingWith(BoudingBox)
But here is what giving me trouble: I wan't them to implement a function for every BoudingVolume
type. So if I have a bounding box and a bounding sphere, both the sphere class and the box class should implement
isCollidingWith(BoundingBox)
isCollidingWith(BoundingSphere)
If i then create a new BoundingVolume like BoundingCylinder
(by deriving from the base class), i want the compiler to throw an error until BoundingBox and BoundingSphere has implemented the isCollidingWith
function for the new Cylinder
type (and ofc until the Cylinder
has implemented the isCollidingWith
for the Box
, Sphere
and the Cylinder
.
Im not sure on how to go about implementing this, but I thought about using CRTPs. Is this even possible?
It is possible to concoct such a thing with CRTP
class BoundingBox;
class BoundingSphere;
class Shape
{
public:
virtual bool isIntersecting(const BoundingBox&) const = 0;
virtual bool isIntersecting(const BoundingSphere&) const = 0;
};
class BoundingVolumeBase
{
public:
virtual bool checkIntersection(const Shape&) const = 0;
virtual ~BoundingVolumeBase();
};
template<class Derived>
class BoundingVolume : public BoundingVolumeBase
{
bool checkIntersection(const Shape& shape) const override
{
return shape.isIntersecting (static_cast<const Derived&>(*this));
}
};
class BoundingBox : public BoundingVolume<BoundingBox> {
// ...
};
class BoundingSphere : public BoundingVolume<BoundingSphere> {
// ...
};
Now if we invent a new kind of BoundingVolume
, it will not compile until a new function is added to Shape
.
class BoundingCylinder : public BoundingVolume<BoundingCylinder> {
// ...
};
BoundingCylinder bc; // <-- this will not compile
It is not necessary to do it this way. Any method that uses virtual functions as the sole kind of type-based dispatch will work (you will likely end up with something roughly equivalent to the above anyway). If you depend on typeid
or on a custom type identifier, you may encounter problems though.
The downside of this method is mutual dependence of class Shape
and all concrete kinds of BoundingVolume
.