我是否应该更改设计以防止动态强制转换? 我读过几篇关于C++中的动态转换的帖子,所有的人都声称它表示糟糕的设计。在其他语言中,我在检查对象的类型时从未考虑过它。我从不把它作为多态性的替代品,而且只有在强耦合似乎完全可以接受的情况下才使用它。我经常遇到的一种情况是:有一个对象列表(我在C++中使用std::vector),所有对象都派生自一个公共基类。列表由允许知道不同子类的对象管理(通常是管理对象类中私有类的一个小层次结构)。通过将它们保存在一个列表(数组、向量等)中,我仍然可以从多态性中获益,但当操作要作用于特定子类的对象时,我使用动态转换或类似的方法

我是否应该更改设计以防止动态强制转换? 我读过几篇关于C++中的动态转换的帖子,所有的人都声称它表示糟糕的设计。在其他语言中,我在检查对象的类型时从未考虑过它。我从不把它作为多态性的替代品,而且只有在强耦合似乎完全可以接受的情况下才使用它。我经常遇到的一种情况是:有一个对象列表(我在C++中使用std::vector),所有对象都派生自一个公共基类。列表由允许知道不同子类的对象管理(通常是管理对象类中私有类的一个小层次结构)。通过将它们保存在一个列表(数组、向量等)中,我仍然可以从多态性中获益,但当操作要作用于特定子类的对象时,我使用动态转换或类似的方法,c++,oop,dynamic-cast,C++,Oop,Dynamic Cast,在没有动态强制转换或类型检查的情况下,有没有一种不同的方法来解决这类问题?我真的很好奇那些不惜一切代价避免这些问题的程序员会如何处理它们 如果我的描述太抽象,我可以在C++中写一个简单的例子(编辑:见下文)。 类EntityContacts{ 私人: 类实体联系人{ 私人: virtualvoid someVirtualFunction(){};//只有在那里才能使动态\u转换工作 公众: b2Contact*m_contactData; }; 类InternalEntityContact:公共

在没有动态强制转换或类型检查的情况下,有没有一种不同的方法来解决这类问题?我真的很好奇那些不惜一切代价避免这些问题的程序员会如何处理它们

<>如果我的描述太抽象,我可以在C++中写一个简单的例子(编辑:见下文)。
类EntityContacts{
私人:
类实体联系人{
私人:
virtualvoid someVirtualFunction(){};//只有在那里才能使动态\u转换工作
公众:
b2Contact*m_contactData;
};
类InternalEntityContact:公共EntityContact{
公众:
内部实体接触(b2Fixture*fixture1、b2Fixture*fixture2){
m_internalFixture1=fixture1;
m_internalFixture2=fixture2;
};
b2Fixture*m_内固定件1;
b2Fixture*m_内固定件2;
};
类ExternalEntityContact:公共EntityContact{
公众:
外部实体接触(b2Fixture*内部夹具,b2Fixture*外部夹具){
m_internalFixture=internalFixture;
m_externalFixture=externalFixture;
};
b2Fixture*m_内部夹具;
b2Fixture*m_外部夹具;
};
物理实体*m_实体;
std::向量m_触点;
公众:
EntityContacts(PhysicsEntity*实体)
{
m_实体=实体;
}
void addContact(b2Contact*contactData)
{
//为内部或外部接触创建对象
EntityContact*新联系人;
if(m_实体->isExternalContact(contactData)){
b2*iFixture;
b2*eFixture;
m_entity->getContactInExfixture(contactData、iTexture、eTexture);
newContact=新的外部实体联系人(iFixture,eFixture);
}
其他的
newContact=new InternalEntityContact(contactData->GetFixtureA(),contactData->GetFixtureB());
//将对象添加到向量
m_触点。推回(新触点);
};
int getExternalEntityContactCount(PhysicsEntity*entity)
{
//返回与实体的外部联系人数
int结果=0;
对于(int i=0;im_externalFixture)==entity)
结果++;
}
返回结果;
}
};
这是我在使用box2d物理的游戏中用于碰撞检测的类的简化版本。我希望box2d的细节不会太分散我想要展示的东西的注意力。我有一个非常类似的类“Event”,它创建了不同类型的事件处理程序,这些事件处理程序的结构相同(使用基类EventHandler的子类而不是EntityContact)

这个

但是当一个操作要作用于一个特定的 子类I使用动态强制转换或类似的东西

听起来对象建模不正确。您有一个包含子类实例的列表,但它们不是真正的子类,因为您不能以相同的方式对它们进行操作(Liskov等)


一种可能的解决方案是扩展基类,这样就有了一组特定子类可以重写的无操作方法。但这听起来仍然不太正确。

问题相当广泛,因此需要考虑以下几点:

  • 这是语言的一个特性,这是有原因的,这意味着存在有效的用例
  • 总的来说,这不是天生的好或坏
  • 检查它是否是您问题的正确解决方案
  • 了解解决问题的备选方案
  • 将它与其他语言进行比较应该包括这样一个问题:C++/C++11的替代方案是否也可以在其他语言中使用
  • dynamic\u cast
    会产生一定的成本。如果是关于运行时性能,请对照备选方案的成本进行检查
  • 检查是在运行时执行的,这会产生一定的风险,如果没有正确测试,您可能会交付有缺陷的软件。通过静态类型检查,编译器可以帮助您,甚至可以保证某些问题/bug不会发生

通常在这种情况下,您不会管理派生对象列表,而是管理引用实际派生对象的接口指针(或基指针)列表。每当您想要对特定对象执行操作时,都可以通过其接口/基类访问该对象,该接口/基类应该公开所有必需的功能。派生类应该用一个特定的实现覆盖公开的基本功能。

至少在我看来,
dynamic\u cast
的存在是有原因的,有时使用它是合理的。这可能是其中之一

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

真正的问题是这样定义您的操作是否有意义。回到典型的以动物为基础的等级制度,如果你在研究鸟类,那么鸟类的等级制度通常是合理的
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;
  }
};
std::vector<Base*> bases;