1

这里用代码解释:

//Sphere and Box inherit from IShape
//
//Sphere methods:
//bool Sphere::Intersect(Sphere* sphere)
//bool Sphere::Intersect(Box* box);
//
//Box methods:
//bool Box::Intersect(Sphere* sphere)
//bool Box::Intersect(Box* box)

IShape* shapeA;
IShape* shapeB;

shapeA= new Sphere();
shapeB= new Box();

bool areTheyIntersecting = shapeA->Intersect(shapeB); //problem is here?

这种使用多态性的方法会起作用吗,还是我必须寻找另一种方法来让类识别彼此的类型,以便他们知道要调用的正确方法?

4

4 回答 4

2

您描述的问题称为双重调度。有很多解决方案。他们都以各种方式吸吮。

它们糟糕的根本原因是双重调度的大小随着类型的数量呈二次方增长,而编写二次方数量的代码总是很糟糕。

一种方法是找出一种方法,将一般的双重分派减少为具有一些特殊情况(如球体球体)的单次分派。

如果类型数量有限,可以有两组虚函数。第一个将 other 作为抽象基类。另一组函数将每个实现类作为可能的参数。抽象基类在每个实现中都实现,调用另一个对象,并将 this 作为不将抽象基作为参数的“其他函数集”的第一个参数。

即,collide(base* other)调用other->collideSpecific (this).

CRTP 可用于减少一些样板。

于 2012-12-22T19:53:54.627 回答
1

对于这种情况,您需要一种称为双重调度的东西。看看 Scott Meyers 的 More Effective C++ 和 Alexendrescu 的 Modern C++ Design。

这是另一篇也讨论它的文章 http://www.drdobbs.com/double-dispatch-revisited/184405527

于 2012-12-22T19:50:53.847 回答
1

一种解决方法是在每个类中声明 uint 变量(或从类中提取,见下文)和一个为相关对象返回此变量的虚函数。然后我会声明一个哈希<std::pair<uint,uint>,std::function<bool(IShape*, IShape*)>>

哈希将包含知道如何处理特定对象类型的函数,典型的调用如下:

auto key = std::pair<uint,uint>(obj1.typeNumber(), obj2.typenumber())
funchash[key](obj1, obj2);

如本手册所示,该数字甚至不需要硬编码:http: //shaderop.com/2010/09/uniquely-identifying-types-in-c-without-using-rtti/index.html 这基本上显示了如何将类名转换为类型 id。

当然,这仍然意味着很多样板,但我不喜欢在我的课程中使用它,而且这种类型的机制本身还是很有用的。

于 2012-12-22T20:16:10.657 回答
1

双重调度通常通过访问者模式使用,但在您的情况下,这有点奇怪,因为访问者本身就是元素......坚持住!

简而言之,这个想法:

  • 从一对IShape/开始IShape,命名leftright从现在开始
  • 在作为参数传递时调用该intersect方法,在该方法中知道它的确切类型(它是一个!)并通过调用on的正确重载来通知它(接受 a 的那个)leftrightintersectleftSphererightintersectrightSphere
  • intersect调用中rightright知道它的确切类型,,我们也传递了确切的类型left,所以现在我们都知道了!

一个简单的实现:

class IShape {
public:
    virtual ~IShape() {}

    virtual bool intersect(IShape const& other) const = 0;

    virtual bool intersect(Box const& other) const = 0;
    virtual bool intersect(Sphere const& other) const = 0;
}; // class IShape

class Box: public IShape {
public:
    virtual bool intersect(IShape const& other) const override {
        std::cout << "-> Box::intersect(IShape)\n";
        return other.intersect(*this);
    }

    virtual bool intersect(Box const& other) const override {
        std::cout << "-> Box::intersect(Box)\n";
        /* compute intersection of two boxes */
        return false;
    }

    virtual bool intersect(Sphere const& other) const override {
        std::cout << "-> Box::intersect(Sphere)\n";
        /* compute intersection of a box and a sphere */
        return false;
    }
}; // class Box

// Likewise implementation of Sphere

一个完整的实现给出了这个输出:

int main() {
   Box const box;
   Sphere const sphere;
   IShape const& ibox = box;
   IShape const& isphere = sphere;


   box.intersect(sphere);
   // output
   // -> Box::intersect(Sphere)


   ibox.intersect(sphere);
   // output
   // -> Box::intersect(Sphere)


   sphere.intersect(ibox);
   // output
   // -> Sphere::intersect(IShape)
   // -> Box::intersect(Sphere)


   isphere.intersect(ibox);
   // output
   // -> Sphere::intersect(IShape)
   // -> Box::intersect(Sphere)
}

这种策略被命名为双重分派,因为从 IShape/IShape 开始时有两个连续的双重分派,每个变量一个分派,需要为其“推导”动态类型。

于 2012-12-22T20:28:54.037 回答