В этой главе мы рассмотрели много материала. Если вы дошли до этого момента, то я вас поздравляю — вы проделали немало работы и это уже хороший шаг на пути к изучению языка C++ в частности и программированию в целом! Сейчас же давайте закрепим пройденный материал.
Теория
Блок стейтментов (или «составной оператор») обрабатывается компилятором так, как если бы это был один стейтмент. Составные операторы помещаются в фигурные скобки {
и }
и используются почти везде.
Локальные переменные создаются в точке определения и уничтожаются при выходе из блока, в котором они объявлены. Доступ к ним возможен только внутри этого же блока.
Глобальные переменные создаются, когда программа запускается, и уничтожаются, когда она завершает свое выполнение. Они могут использоваться в любом месте программы. Неконстантные глобальные переменные следует избегать, потому что это — зло.
Ключевое слово static может использоваться для преобразования глобальной переменной во внутреннюю (с внутренней связью), чтобы её можно было использовать только в том файле, в котором она объявлена. Также ключевое слово static используют для указания того, что локальная переменная должна иметь статическую продолжительность жизни. А это означает, что она будет сохранять свое значение даже после выхода из своей области видимости.
Пространство имен — это область, в которой гарантируется уникальность всех имен. Отличный способ избежать конфликтов имен. Не используйте using-стейтменты вне тела функций.
Неявное преобразование типов данных происходит, когда один тип данных конвертируется в другой тип без использования одного из операторов явного преобразования. Явное преобразование типа происходит, когда один тип данных конвертируется в другой с помощью одного из операторов явного преобразования. В некоторых случаях это абсолютно безопасно, в других случаях данные могут быть потеряны. Избегайте использования конвертации C-style, вместо нее используйте оператор static_cast.
std::string — это простой способ работы с текстовыми строками (текст помещается в двойные кавычки).
Перечисления позволяют создавать собственные (пользовательские) типы данных. Классы enum — это те же перечисления, но надежнее и безопаснее. Используйте их вместо обычных перечислений, если ваш компилятор поддерживает C++11.
typedef позволяет создавать псевдонимы для типов данных. Целочисленные типы данных с фиксированным размером реализованы с помощью typedef. Псевдонимы типов полезны для присваивания простых имен сложным типам данных.
И, наконец, структуры. Они позволяют сгруппировать отдельные переменные в единое целое. Доступ к членам структуры осуществляется через оператор выбора членов (.
). Объектно-ориентированное программирование в значительной степени основывается именно на структурах, поэтому, если вы изучили только одну вещь из этой главы, то лучше, чтобы это были структуры.
Тест
При разработке игры мы решили, что в ней должны быть монстры, потому что всем нравится сражаться с монстрами. Объявите структуру, которая представляет вашего монстра. Монстр может быть разным: ogre
, goblin
, skeleton
, orc
и troll
. Если ваш компилятор поддерживает C++11, то используйте классы enum, если нет — обычные перечисления.
Каждый монстр также должен иметь имя (используйте std::string) и количество здоровья, которое отображает, сколько урона он может получить, прежде чем умрет. Напишите функцию printMonster(), которая выведет все члены структуры. Объявите монстров типа goblin
и orc
, инициализируйте их, используя список инициализаторов, и передайте в функцию printMonster().
Пример результата выполнения вашей программы:
This Goblin is named John and has 170 health.
This Orc is named James and has 35 health.
Ответ C++11
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
#include <iostream> #include <string> // Определяем класс enum с типами монстров enum class MonsterType { OGRE, GOBLIN, SKELETON, ORC, TROLL }; // Наша структура представляет одного монстра struct Monster { MonsterType type; std::string name; int health; }; // Возвращаем тип монстра в виде строки std::string getMonsterTypeString(Monster monster) { if (monster.type == MonsterType::OGRE) return "Ogre"; if (monster.type == MonsterType::GOBLIN) return "Goblin"; if (monster.type == MonsterType::SKELETON) return "Skeleton"; if (monster.type == MonsterType::ORC) return "Orc"; if (monster.type == MonsterType::TROLL) return "Troll"; return "Unknown"; } // Выводим информацию о монстре void printMonster(Monster monster) { std::cout << "This " << getMonsterTypeString(monster); std::cout << " is named " << monster.name << " and has " << monster.health << " health.\n"; } int main() { Monster goblin = { MonsterType::GOBLIN, "John", 170 }; Monster orc = { MonsterType::ORC, "James", 35 }; printMonster(goblin); printMonster(orc); return 0; } |
Ответ до С++11
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
#include <iostream> #include <string> // Определяем перечисление с типами монстров enum MonsterType { MONSTER_OGRE, MONSTER_GOBLIN, MONSTER_SKELETON, MONSTER_ORC, MONSTER_TROLL }; // Наша структура представляет одного монстра struct Monster { MonsterType type; std::string name; int health; }; // Возвращаем тип монстра в виде строки std::string getMonsterTypeString(Monster monster) { if (monster.type == MONSTER_OGRE) return "Ogre"; if (monster.type == MONSTER_GOBLIN) return "Goblin"; if (monster.type == MONSTER_SKELETON) return "Skeleton"; if (monster.type == MONSTER_ORC) return "Orc"; if (monster.type == MONSTER_TROLL) return "Troll"; return "Unknown"; } // Выводим информацию о монстре void printMonster(Monster monster) { std::cout << "This " << getMonsterTypeString(monster); std::cout << " is named " << monster.name << " and has " << monster.health << " health.\n"; } int main() { Monster goblin = { MONSTER_GOBLIN, "John", 170}; Monster orc = { MONSTER_ORC, "James", 35}; printMonster(goblin); printMonster(orc); return 0; } |
Собственно не понятно следующее: ожидаю что строка
будет возвращать хотя бы Тип: MonstersType::ogre. Это не красиво, но хотя бы логично. Но фактически от такого варианта программа ломается и компиляция не происходит. Приходится городить if/else, что на мой взгляд портит всю прелесть соединения перечислений со структурой. Почему так? Можно ли сделать вывод di.type по другому, без использования if/else?
Тоже микро игру сделал
Капец, сделал архитектуру программки, все сделал правильно, а в итоге получил 9 ошибок и 5 сообщений, а как только поменял местами структуру и перечисление типов монстров, все стало работать отлично.
Сделал небольшую игру)
Не судите строго, пожалуйста)
Я в принципе сделал проще,как в примере.
Да,полностью не так как нужно,зато получилось.
Я просто не понял,как делать именно по заданию.
Объясните пожалуйста.
p.s я в ответ не заглянул,ибо не хочу списывать.
Понимаю,что код плохой, но я только начал программировать.
// Example program
Добрый день!
Знаете, если честно, я так и не понял преимущества использования enum. Я написал две программы. Принципиально с enum, чтобы разобраться с ними, и без enum, так, как на мой взгляд проще. И могу сказать, что без enum действительно получилось намного проще и, на мой взгляд, код тоже читать проще.
Вот и сижу, мучаюсь догадками. Есть три предположения=))
1) Вы плохо объяснили все преимущества перечислителей. В этом я сильно сомневаюсь, т.к. всем предыдущие уроки прошли на ура, Вы очень хорошо расписываете материал=)
2) "На вкус и цвет товарищей нет" — т.е. каждый работает по своему, у каждого свои принципы работы и каждый делает так, как ему удобно (не пренебрегая, конечно, общими правилами, чтобы други могли разобраться в коде)
3) Перечислители действительно не так уж и полезны, как утверждают некоторые кодеры=)
Очень интересно узнать Ваше мнение по этому поводу=)Заранее спасибо!
Вот те самые программы с enum и без (программа без enum была написана последней, поэтому в ней, опять же на мой взгляд, лучше подобраны имена переменных и т.п.). Без перечислителей:
____________________________________
Вариант с enum:
Возможно, экономия памяти. Если к примеру известно что переменная может хранить значение только "Самолёт взлетел", "Самолёт летит" и "Самолёт приземлился", "Самолёт разбился",то для этого можно использовать перечисление. Тогда переменная будет иметь объём 4 байта (на моём компиляторе, VS 2019 Windows 10 x64, на другом может быть будет по-другому). Причём даже не важно, будут строки эти длиннее или короче, чем мною приведённые. А если использовать для этого строки, то понадобится не меньше 20 байт. Но это опять таки только догадка, возможно, у перечислений есть ещё какие-то преимущества.
PS. В универе нам тоже не объяснили накой перечисления сдались. Зато во всю заставляли использовать)))))
Игра против компьютера…
Так же решил создать мини игру, на основании изученного с данного сайта материала.
Комментировал на сколько мог, надеюсь кому то пригодится для разбора.
Спасибо автору сайта, за предоставленную возможность.
П.С. Циклы просматривал до этого, с другого сайта (но мельком). 🙂
В строке
опечатка/ошибка.
Должно быть
Вот, исходя из всех уроков 4-й главы, сделал такую вот игру с монстрами. Прошу прощения за длинный код.
Реально прикольно получилось 🙂 Долго делал?
Ну где-то часик 🙂
Нормально.
Уважаемый rpa4! Подскажите мне, пожалуйста, как Вы кодите предложение, в котором тип монстра задаётся буквами, а не как у меня — числом:
Тоже была такая же идея) Но я что-то не пойму, я что, где-то пропустил циклы в предыдущих уроках?
Уважаемый автор, какой смысл функцией getMonsterTypeString(Monster monster) проверять логические условия, если типы "монстров" и так объявлены в enum class MonsterType?
Заранее спасибо!
В getMonsterTypeString мы присваиваем значения для MonsterType::GOBLIN и MonsterType::ORC — Goblin и Ork соответственно. Если бы мы не использовали getMonsterTypeString, то вместо MonsterType::GOBLIN выводилось бы 1, а вместо MonsterType::ORC — 3. Функция getMonsterTypeString — это инициализация элементов структуры и заодно проверка.
Про инициализацию элементов структуры я не сообразил. Спасибо!