C++将基类指针转换为派生类,不知道派生类

san*_*e11 5 c++ pointers casting base-class derived-class

我有各种类型的碰撞器类(SphereCollider、AABBCollider 等),它们都继承自基类 Collider。我使用指向基类的指针将它们存储在 std::vector 中。

std::vector<std::shared_ptr<Collider>> colliders;
Run Code Online (Sandbox Code Playgroud)

然后我有各种函数来确定对撞机是否彼此相交。

bool Colliding(const SphereCollider& colliderOne, const SphereCollider& colliderTwo);
bool Colliding(const AABBCollider& colliderOne, const AABBCollider& colliderTwo);
bool Colliding(const AABBCollider& colliderOne, const SphereCollider& colliderTwo);
bool Colliding(const SphereCollider& colliderOne, const AABBCollider& colliderTwo);
Run Code Online (Sandbox Code Playgroud)

我的想法是简单地遍历碰撞器向量,然后将每个碰撞器与列表中的所有其他碰撞器进行比较。

for (unsigned int a = 0; a < colliders.size(); ++a)
{
    for (unsigned int b = a + 1; b < colliders.size(); ++b)
    {
        // Store the two colliders we're current comparing
        std::shared_ptr<Collider> colliderOne = colliders[a];
        std::shared_ptr<Collider> colliderTwo = colliders[b];

        // Somehow cast pointers back to correct derived type

        // Check colliding
        if(Colliding(*colliderOneDerived, *colliderTwoDerived))
        {
            // Colliding
        }

    }
}
Run Code Online (Sandbox Code Playgroud)

但是,要成功执行此操作,我需要将指针转换回正确的派生类型,以便调用正确的函数,但我不知道每次碰撞器都是什么类型。

基碰撞器类有一个 Type() 函数,它从基指针正确返回派生类型。

std::type_index Collider::Type() { return typeid(*this); }
Run Code Online (Sandbox Code Playgroud)

有没有办法可以使用它来将指针转换为正确的派生类型?

chm*_*ike 0

用于dynamic_pointer_cast获取派生类上的共享指针。nullptr如果派生类的类型错误,则返回指针。

std::shared_ptr<SphereCollider> sc = std::dynamic_pointer_cast<SphereCollider>(colliderOne);
Run Code Online (Sandbox Code Playgroud)

scnullptr如果colliderOne不是类型,则为SphereCollider。否则它将指向SphereCollider.

通过使用此方法,您可以实现动态调度。

更新:

下面是如何使用智能指针向下转型来实现动态调度的示例。

std::shared_ptr<SphereCollider> sc1, sc2;
std::shared_ptr<AABBCollider> aabc1, aabc2;
...

if (sc1 = std::dynamic_pointer_cast<SphereCollider>(colliderOne))
{
    if (sc2 = std::dynamic_pointer_cast<SphereCollider>(colliderTwo))
        Colliding(*sc1, *sc2);
    else if (aabc2 = std::dynamic_pointer_cast<AABBCollider>(colliderTwo))
        Colliding(*sc1, *aabc2);
    ...
}
else if (aabc1 = std::dynamic_pointer_cast<AABBCollider>(colliderOne))
{
    if (sc2 = std::dynamic_pointer_cast<SphereCollider>(colliderTwo))
        Colliding(*aabc1, *sc2);
    else if (aabc2 = std::dynamic_pointer_cast<AABBCollider>(colliderTwo))
        Colliding(*aabc1, *aabc2);
    ...
}
...
Run Code Online (Sandbox Code Playgroud)

使用哈希表优化动态调度

如果您有许多不同类型的 Collider 类,则上面的代码可能不是很有效。它在类中执行线性搜索来执行调度。

通过向返回类名的 Collider 类添加一个字段,您可以连接两个类名来构建一个键。然后,您可以使用 std::unordered_map带有 lambda 的 an 作为关联值。lambda 将接收这两个参数std::shared_ptr<Collider>作为参数。它将执行向下转换并调用 Collider 函数。

如果您需要,我会显示代码。