c++ - 将 shared_ptr<Base> 作为 shared_ptr<Derived> 传递

标签 c++ inheritance polymorphism shared-ptr double-dispatch

我目前有以下结构

class A

class B : public A

class C : public A

我在 A 中定义了虚拟方法和 BC正在压倒他们。这些方法是这样的

bool C::CheckCollision(shared_ptr<B> box);

bool B::CheckCollision(shared_ptr<C> triangle);

我还有一个 vector shared_ptr<A>我在其中存储所有游戏对象。问题是我无法执行以下操作

for (int i = 0; i < objects.size(); i++)
{
    for (int j=i; j < objects.size(); j++
    {
        objects[i]->CheckCollision(objects[j]);
    }

}

我收到一条错误消息,指出参数列表与重载函数不匹配。有道理,因为我试图通过 shared_ptr<A>我期待的地方shared_ptr<B>shared_ptr<C> ,但我该如何解决这个问题呢?还有其他方法吗?

最佳答案

让我们让它与虚函数和指向基类的共享指针一起工作

首先,您可以使用指向基的共享指针来完美地实现多态性。这里有一个小片段向您展示了如何做到这一点:

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 .
    }
}

现在,您看,为了掌握这些组合,我使用了一个重写,它知道自己对象的真实类型,但不知道伙伴对象的真实类型的任何具体信息。因此,要确定它是哪种配对,我需要调用伙伴对象的多态函数。

Online demo

解决您的问题的更一般方法是双重分派(dispatch)

这个小的概念证明是为了展示一个简单的例子。理想情况下,问题可以分解为每个合作伙伴对象执行问题的一部分。但事情并不总是那么简单,因此您可以通过谷歌搜索 double dispatch 找到更精细的技术。 。幸运的是,碰撞的例子很常见。

在这里another demo它结合了覆盖和重载。我认为这是您尝试实现的事情,但可以通过更多的间接级别来解决。是inspired by the visitor pattern : 一个对象的多态碰撞函数是用指向伙伴对象基类的共享指针调用的。但是这个函数的实现会立即调用伙伴对象的多态函数,并将对自身的引用作为参数(即参数的真实类型的知识,允许编译器选择正确的重载)。不幸的是,这种“反弹”方法(顺便说一句,它是一种反向访问者)要求基类知道它所有潜在的派生类,这远非理想。但它允许为每种可能的组合提供不同的行为。

双重分派(dispatch)的另一种方法是使用 dispatch table .这是通过管理一种虚拟表但有两种类型,并进行一些查找来为正确的组合调用正确的函数来工作的。

关于c++ - 将 shared_ptr<Base> 作为 shared_ptr<Derived> 传递,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54968690/

相关文章:

c++ - 如何正确实现与基类不同的版本?

c++ - 多态实例返回多态实例

c++ - 声明 vector 时出现段错误

c++ - 如何模拟依赖的成员变量?

c++ - 未调用虚拟方法

c# - 如何编写为模板化基指定类型参数的派生类

C++, boost : How to store objects of an abstract type in a map container

c++ - 模板化构造函数中的奇怪错误

c++ - 在C++中推导继承方法的父类

c++ - 从模板类继承繁琐