|
Программирование >> Оптимизация возвращаемого значения
практическим выходом будет возврат к механизму двойного вызова виртуальных функций, который был рассмотрен ранее. Значит, вам придется примириться с необходимостью перекомпиляции при введении новых классов в иерархию наследования. Инициализация эмулированных таблиц виртуальных функций (повторно) Это все, что можно сказать о двойной диспетчеризации, но неприятно заканчивать главу на такой грустной ноте. Поэтому вашему вниманию предлагается набросок альтернативного подхода к инициализации массива collisionMap. Схема программы до сих пор оставалась полностью статической. Будучи раз зарегистрирована, функция для обработки столкновений объектов двух разных типов остается навсегда. А что, если пользователю захочется добавлять, удалять или изменять функции для обработки столкновений во время игры? Чтобы сделать это, можно заключить понятие карты, хранящей функции обработки столкновений, в класс, где находятся функции-члены, позволяющие динамически изменять содержимое карты, например: class CollisionMap { public: typedef void (*HitFunctionPtr) (GameObjectSc, GameObjectSc); void addEntry (const stringSc typel, const stringSc type2, HitFunctionPtr collisionFunction, bool symmetric = true); См. ниже, void removeEntry (const stringSc typel, const stringSc type2) ; HitFunctionPtr loolcup(const stringSc typel, const StringSc type2) ; Эта функция возвращает ссылку на одну и только одну карту - см. правило 26. static CollisionMapSc theCollisionMap(); private: Эти функции объявлены как закрытые, чтобы предотвратить создание нескольких карт - см. правило 26. CollisionMapО; CollisionMap (const CollisionMapSc); Этот класс позволяет добавлять в карту игры новые элементы, удалять их из нее и выполнять поиск функции обработки столкновений, связанную с определенной парой имен типов. Он также использует методы из правила 26, чтобы создавался всего один объект CollisionMap, так как в системе существует всего одна карта. (Можно легко представить себе более сложные игры с несколькими картами.) И наконец, она позволяет упростить добавление к карте симметричных столкновений (то есть если столкновение объекта типа Т1 с объектом типа Т2 имеет тот же эффект, что и столкновение объекта типа Т2 с объектом типа Т1), CollisionMap::theCollisionMap().addEntry(typel, type2, collisionFunction, symmetric); После этого пользователи могли бы с помощью глобальных объектов данного типа автоматически регистрировать необходимые им функции: RegisterCollisionFunction cf1( Spaceship , Asteroid , ScshipAsteroid) ; автоматически добавляя соответствующую ячейку карты при вызове функции addEntry со значением необязательного параметра symmetric равным true. Имея такой класс CollisionMap, каждый из пользователей, которому нужно добавить ячейку к карте, делает это напрямую: void shipAsteroid(GameObjectSc spaceship, GameObjectSc asteroid) ; CollisionMap::theCollisionMap(.addEntry( Spaceship , Asteroid , ScshipAsteroid) ; void shipStation(GameObjectSc spaceship, GameObjectSc SpaceStation) ; CollisionMap::theCollisionMap().addEntry( Spaceship , SpaceStation , ScshipStation) ; void asteroidstation(GameObjectSc asteroid, GameObjectSc SpaceStation) ; CollisionMap::theCollisionMap().addEntry( Asteroid , SpaceStation , ScasteroidStation) ; Нужно гарантировать, что ячейки карты будут добавлены до того, как произойдут столкновения, вызывающие связанные с ними функции. Один из способов сделать это - проверять в конструкторах подклассов класса GameObj ect, что соответствующие изображения уже были добавлены к карте при создании каждого объекта. Но такой подход немного снизит производительность программы. В качестве альтернативы можно было бы создать класс Register-CollisionFunction: class RegisterCollisionFunction { public: RegisterCollisionFunction( const StringSc typel, const StringSc type2, CollisionMap::HitFunctionPtr collisionFunction, bool symmetric = true) RegisterCollisionFunction cf2{ Spaceship , SpaceStation , ScshipStation) ; RegisterCollisionFunction cf3( Asteroid , SpaceStation , basteroidStation); int main(int argc, char * argv[]) { Так как эти объекты создаются до вызова функции main, то функции, регистрируемые их конструкторами, также добавляются к карте до вызова функции main. Если позже в игру включается новый производный класс: class Satellite: public GameObject { ... } ; И одна или несколько новых функций для обработки столкновений: void satelliteShip(GameObjectSc satellite, GameObjectSc spaceship); void satelliteAsteroid(GameObject6c satellite, GameObjectSc asteroid); TO все новые функции вы сможете добавить к карте аналогичным образом, не затрагивая соответствующий код: RegisterCollisionFunction cf4( Satellite , Spaceship , ScsatelliteShip) ; RegisterCollisionFunction cf5{ Satellite , Asteroid , ScsatelliteAsteroid) ; Конечно, это далеко не безупречный способ реализации множественной диспетчеризации (такого попросту нет), но он облегчает ввод данных в основанную на карте реализацию.
|
© 2006 - 2025 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |