Я прочитал несколько тем о динамических приведениях в С++, и все они полны людей, утверждающих, что это указывает на плохой дизайн. В других языках я никогда особо не задумывался при проверке типа объекта. Я никогда не использую его как альтернативу полиморфизму и только тогда, когда сильная связь кажется вполне приемлемой. С одной из таких ситуаций я сталкиваюсь довольно часто: у меня есть список (я использую std::vector в C++) объектов, производных от общего базового класса. Список управляется объектом, которому разрешено знать различные подклассы (часто это небольшая иерархия частных классов внутри класса управляющих объектов). Сохраняя их в одном списке (массив, вектор, ..), я все еще могу извлечь выгоду из полиморфизма, но когда операция предназначена для воздействия на объекты определенного подкласса, я использую динамическое приведение или что-то подобное.
Есть ли другой подход к этому типу проблем без динамического приведения или проверки типов, который мне не хватает? Мне действительно любопытно, как с ними справятся программисты, которые любой ценой избегают этого.
Если мое описание слишком абстрактно, я могу написать простой пример на 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).
instanceof
в Java также не одобряется. Есть законные способы использования, но в целом это не соответствует концепциям OO. С точки зрения объектно-ориентированного программирования можно спросить, зачем объекту-менеджеру знать о подклассах, если действие над конкретным подклассом должно быть абстрагировано и т. д. - person msam   schedule 21.03.2013dynamic_cast
кажется мне ярлыком дизайна. Все можно сделать производным от общего базового класса (class Base {};
) и сохранить в списке (std::list<Base> l
). Но когда мы используемdynamic_cast
позже, это приводит к нескольким вопросам: должны ли мы использовать наследование? Или мы достаточно абстрагировались? - у нас есть другие доступные инструменты (шаблоны и интерфейсы) - person andre   schedule 21.03.2013