我已经阅读了一些有关C++中动态转换的主题,所有人都声称它表明设计不良。在其他语言中,检查对象的类型时从来没有考虑过。我绝不将其用作多态性的替代方法,只有在强耦合似乎完全可以接受时才使用。我经常遇到以下情况之一:拥有一个对象列表(我在C++中使用std::vector),所有对象都来自一个公共(public)基类。该列表由一个对象管理,该对象被允许知道不同的子类(通常是管理对象类中的私有(private)类的较小层次结构)。通过将它们保存在单个列表(数组, vector 等)中,我仍然可以从多态中受益,但是当操作要作用于特定子类的对象时,我可以使用动态转换或类似方法。

没有动态转换或我缺少的类型检查,是否有其他方法可以解决此类问题?我真的很好奇,不惜一切代价避免这些的程序员将如何处理它们。

如果我的描述太抽象了,我可以用C++写一个简单的例子(编辑:见下文)。

class EntityContacts {
private:
  class EntityContact {
  private:
    virtual void someVirtualFunction() { };            // Only there to make dynamic_cast work
  public:
      b2Contact* m_contactData;
  };

  class InternalEntityContact : public EntityContact {
  public:
    InternalEntityContact(b2Fixture* fixture1, b2Fixture* fixture2){
        m_internalFixture1 = fixture1;
        m_internalFixture2 = fixture2;
    };

    b2Fixture* m_internalFixture1;
    b2Fixture* m_internalFixture2;
  };

  class ExternalEntityContact : public EntityContact {
  public:
    ExternalEntityContact(b2Fixture* internalFixture, b2Fixture* externalFixture){
        m_internalFixture = internalFixture;
        m_externalFixture = externalFixture;
    };

    b2Fixture* m_internalFixture;
    b2Fixture* m_externalFixture;
  };

  PhysicsEntity* m_entity;
  std::vector<EntityContact*> m_contacts;
public:
  EntityContacts(PhysicsEntity* entity)
  {
    m_entity = entity;
  }

  void addContact(b2Contact* contactData)
  {
    // Create object for internal or external contact
    EntityContact* newContact;
    if (m_entity->isExternalContact(contactData)) {
        b2Fixture* iFixture;
        b2Fixture* eFixture;
        m_entity->getContactInExFixtures(contactData, iFixture, eFixture);
        newContact = new ExternalEntityContact(iFixture, eFixture);
    }
    else
        newContact = new InternalEntityContact(contactData->GetFixtureA(), contactData->GetFixtureB());

    // Add object to vector
    m_contacts.push_back(newContact);
  };

  int getExternalEntityContactCount(PhysicsEntity* entity)
  {
    // Return number of external contacts with the entity
    int result = 0;
    for (int i = 0; i < m_contacts.size(); ++i) {
        ExternalEntityContact* externalContact = dynamic_cast<ExternalEntityContact*>(m_contacts[i]);
        if (externalContact != NULL && getFixtureEntity(externalContact->m_externalFixture) == entity)
            result++;
    }
    return result;
  }
};

它是类的简化版本,我在使用box2d物理的游戏中用于碰撞检测。我希望box2d的细节不会使我分散注意力。我有一个非常相似的类'Event',它创建以相同方式构造的不同类型的事件处理程序(使用基类EventHandler的子类而不是EntityContact)。

最佳答案

至少从我的角度来看,dynamic_cast存在是有原因的,有时使用它是合理的。这可能是其中之一。

根据您描述的情况,一种可能的替代方法是在基类中定义更多所需的操作,但是如果您为基类或不支持这些功能的其他类调用它们,则将它们定义为(可能是无提示的)失败操作。

真正的问题是用这种方式定义您的操作是否有意义。回到典型的基于动物的层次结构,如果您使用的是Birds,则通常对Bird类定义一个fly成员是明智的,而对于少数不能飞行的鸟,只是让它失败(理论上应该是重命名为attempt_to_fly之类的东西,但很少有太大作为)。

如果您看到很多这样的内容,则可能表明您的类中缺乏抽象-例如,您可能真的需要fly成员,而不是attempt_to_flytravel,这取决于具体的动物是否通过游泳,爬行,散步,飞行等方式做到这一点

09-12 13:59