将 shared_ptr<Base> 作为 shared_ptr<Derived> 传递
Passing shared_ptr<Base> as shared_ptr<Derived>
我目前有以下结构
class A
class B : public A
class C : public A
我在 A
中定义了虚拟方法,B
和 C
覆盖了它们。这些方法属于
bool C::CheckCollision(shared_ptr<B> box);
bool B::CheckCollision(shared_ptr<C> triangle);
我还有一个 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
首先,您可以使用指向基的共享指针完美地实现多态性。这里有一个小片段向您展示了如何做到这一点:
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 .
}
}
现在,你看,为了掌握这些组合,我使用了一个覆盖,它知道自己对象的真实类型,但不知道任何关于伙伴对象真实类型的具体信息。因此,要确定它是哪种配对,我需要调用伙伴对象的多态函数。
解决您的问题的更通用方法是双重分派
这个小的概念证明是为了展示一个简单的例子。理想情况下,问题可以分解为每个合作伙伴对象执行问题的一部分。但事情并不总是那么简单,因此您可以通过谷歌搜索 double dispatch 找到更精细的技术。幸运的是,碰撞的例子很常见。
这里another demo that uses a combination of overriding and overloading. I think this is the kind of things you try to achieve but solves it through one level of indirection more. It is inspired by the visitor pattern: 一个对象的多态碰撞函数是用指向伙伴对象基class的共享指针调用的。但是这个函数的实现会立即调用伙伴对象的多态函数,并将对自身的引用作为参数(即参数的真实类型的知识,允许编译器 select 正确的重载)。不幸的是,这种 "bounce-back" 方法(顺便说一句,它是一种反向访问者)需要基数 class 知道它的所有潜在派生 class,这远非理想。但它允许为每种可能的组合提供不同的行为。
双重分派的另一种方法是使用dispatch table。这是通过管理一种虚拟 table 但有两种类型,并进行一些查找来为正确的组合调用正确的函数来工作的。
我目前有以下结构
class A
class B : public A
class C : public A
我在 A
中定义了虚拟方法,B
和 C
覆盖了它们。这些方法属于
bool C::CheckCollision(shared_ptr<B> box);
bool B::CheckCollision(shared_ptr<C> triangle);
我还有一个 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
首先,您可以使用指向基的共享指针完美地实现多态性。这里有一个小片段向您展示了如何做到这一点:
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 .
}
}
现在,你看,为了掌握这些组合,我使用了一个覆盖,它知道自己对象的真实类型,但不知道任何关于伙伴对象真实类型的具体信息。因此,要确定它是哪种配对,我需要调用伙伴对象的多态函数。
解决您的问题的更通用方法是双重分派
这个小的概念证明是为了展示一个简单的例子。理想情况下,问题可以分解为每个合作伙伴对象执行问题的一部分。但事情并不总是那么简单,因此您可以通过谷歌搜索 double dispatch 找到更精细的技术。幸运的是,碰撞的例子很常见。
这里another demo that uses a combination of overriding and overloading. I think this is the kind of things you try to achieve but solves it through one level of indirection more. It is inspired by the visitor pattern: 一个对象的多态碰撞函数是用指向伙伴对象基class的共享指针调用的。但是这个函数的实现会立即调用伙伴对象的多态函数,并将对自身的引用作为参数(即参数的真实类型的知识,允许编译器 select 正确的重载)。不幸的是,这种 "bounce-back" 方法(顺便说一句,它是一种反向访问者)需要基数 class 知道它的所有潜在派生 class,这远非理想。但它允许为每种可能的组合提供不同的行为。
双重分派的另一种方法是使用dispatch table。这是通过管理一种虚拟 table 但有两种类型,并进行一些查找来为正确的组合调用正确的函数来工作的。