让我们让它与虚函数和指向基类的共享指针一起工作
首先,您可以完美地使多态性工作,使用指向基的共享指针。这里有一个小片段向您展示如何做到这一点:
class A {
public:
virtual void show() { cout<<"A"<<endl; }
virtual void collide(shared_ptr<A> a) { cout<<"collide A with "; a->show(); }
virtual ~A() {}
};
class B : public A {
public:
void show() override { cout<<"B"<<endl; }
void collide(shared_ptr<A> a) override { cout<<"collide B with "; a->show(); }
};
class C : public A {
public:
void show() override { cout<<"C"<<endl; }
void collide(shared_ptr<A> a) override { cout<<"collide C with "; a->show(); }
};
您的双循环将如下所示:
vector<shared_ptr<A>> objects;
objects.push_back (make_shared<A>()); // populate for the sake of demo
objects.push_back (make_shared<B>());
objects.push_back (make_shared<C>());
for (int i = 0; i < objects.size(); i++)
{
objects[i]->show();
for (int j=i; j < objects.size(); j++)
{
objects[i]->collide(objects[j]); // note that you have to use -> not .
}
}
现在,你看,为了掌握组合,我使用了一个覆盖,它知道它自己的对象的真实类型,但不知道任何关于伙伴对象的真实类型的具体信息。所以要弄清楚它是哪种配对,我需要调用伙伴对象的多态函数。
在线演示
解决问题的更一般方法是双重调度
这个小的概念证明是为了展示一个简单的例子。理想的情况是问题可以分解为每个合作伙伴对象执行问题的一部分。但事情并不总是那么简单,所以你可以通过谷歌搜索双重调度找到更复杂的技术。幸运的是,碰撞的例子很常见。
这是另一个使用覆盖和重载组合的演示。我认为这是您尝试实现的那种事情,但通过更多的间接级别来解决它。它的灵感来自于访客模式: 对象的多态碰撞函数是用一个指向伙伴对象基类的共享指针调用的。但是这个函数的实现会立即调用伙伴对象的一个多态函数,并以对自身的引用作为参数(即参数的真实类型的知识,允许编译器选择正确的重载)。不幸的是,这种“反弹”方法(顺便说一下,它是一种倒置的访问者)需要基类知道其所有潜在的派生类,这远非理想。但它允许为每种可能的组合提供不同的行为。
双重分派的另一种方法是使用分派表。这通过管理一种具有两种类型的虚拟表来工作,并进行一些查找以调用正确的函数以获得正确的组合。