我正在使用边界框/碰撞检测系统,并且正在使用不同类型的边界卷,像所有边界卷一样使用id来派生相同的基类,然后使用纯虚函数强制所有派生类实现诸如

  • isCollidingWith(BoudingBox)

  • 但这给我带来了麻烦:我不希望他们为每种BoudingVolume类型实现一个功能。因此,如果我有一个边界框和一个边界球,那么球形类和框类都应实现
  • isCollidingWith(BoundingBox)
  • isCollidingWith(BoundingSphere)

  • 如果然后我创建一个类似于BoundingCylinder的新BoundingVolume(通过从基类派生),则我希望编译器抛出错误,直到BoundingBox和BoundingSphere为新的isCollidingWith类型实现Cylinder函数为止(并且在Cylinder实现了isCollidingWith之前一直如此)用于BoxSphereCylinder

    我不确定如何实现此目标,但我考虑过使用CRTP。
    这有可能吗?

    最佳答案

    可以使用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> {
        // ...
    };
    

    现在,如果我们发明了一种新的BoundingVolume,则必须在Shape中添加新功能后才能编译。
    class BoundingCylinder : public BoundingVolume<BoundingCylinder> {
        // ...
    };
    
    BoundingCylinder bc; // <-- this will not compile
    

    不必这样做。将虚拟函数用作唯一的基于类型的调度的任何方法都可以使用(无论如何,您最终可能会得到与上述大致等效的结果)。如果您依赖typeid或自定义类型标识符,则可能会遇到问题。

    该方法的缺点是Shape类和所有具体BoundingVolume相互依赖。

    10-06 01:54