C ++ проблема дизайна - PullRequest
       16

C ++ проблема дизайна

2 голосов
/ 11 января 2010

У меня есть иерархия классов как таковая:

Entity  
    Stationary  
        Tree  
    Creature  
        Bear  
        Crow  

И у меня есть Мир и Игрок. Когда игрок сталкивается с чем-то, он получает вызов handleCollision (Entity * entity), а затем в зависимости от того, что происходит, происходят разные вещи; если игрок врезается в дерево, то ничего не происходит, пока игрок атакует, если это медведь. Проблема в том, что я не уверен, как правильно различать дела.

Одна мысль, которая пришла в голову, - это нечто подобное. Player :: handleCollision (Entity *) вызывает Entity-> handleCollisionHelper (Player &). Это виртуальная функция, которая в Tree ничего не делает, а в Creature (она должна атаковать все существа) вызывает Player.handleCollisionCreature (this), а затем помещает код атаки в handleCollisionCreature. Есть ли лучший способ сделать это без использования RTTI (typeid и т. Д.)?

Ответы [ 4 ]

3 голосов
/ 11 января 2010

Виртуальный метод с (Player & player) arg кажется очень хорошим дизайном OO. Как вы сказали, вы могли бы добавить некоторую форму типа или использовать RTTI и переключать регистр через перестановки, но это был бы очень функциональный стиль в стиле C. Пока вы не делаете тысячи виртуальных вызовов в секунду, все будет в порядке.

2 голосов
/ 11 января 2010

Просто для предоставления ссылки на официальное имя - эта проблема называется Double Dispatch (вам нужно решить, что делать, основываясь на типе двух объектов одновременно).

См. Статью в Википедии http://en.wikipedia.org/wiki/Double_dispatch для некоторых деталей и предлагаемого решения.

0 голосов
/ 11 января 2010

Я думаю, что вы ищете, называется " двойная отправка " или " мультиметоды ".

Вызов различных функций в зависимости от динамического типа более чем одного объекта не является встроенной функцией C ++, но есть ряд хорошо известных методов, которые можно использовать самостоятельно. Каскадные звонки, как вы предлагаете, являются, вероятно, наиболее распространенными.

0 голосов
/ 11 января 2010

Вместо вызова на Entity *, почему у вас нет ничего подобного:

 handleCollision(Stationary& stationary)
 {
     // Nothing to do yet?
 }

и

 handleCollision(Creature& creature)
 {
     creature.StartCombat(this);
 }

И удалите функцию Entity *. Это гарантирует, что только существа начнут сражаться (добавьте функцию StartComabt в ваш класс Существ). С другой стороны, вы можете иметь класс боя:

 handleCollision(Creature& creature)
 {
     Combat::Begin(this, creature);
 }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...