Урок 4. Перечисления и кортежи в C++

На занятии объясняется тема «Перечисления в C++»

Теория

Перечисления

Объявление типа enum может находиться в cpp-файле в верхней части кода (то есть вне функций), а также в заголовочных файлах.

int main()
{
  enum MyType { A, B, C }; // A=0 B=1 C=2
  enum YourType { D = 2, E, F = 0 }; // E=3
  MyType m = A;
}
Перечисления связаны со значением базового типа. Когда инициализаторы предоставляются в списке-перечислителей (элементов перечяисления), значения перечислителей определяются этими инициализаторами. Если первый перечислитель не имеет инициализатора, то связанное с ним значение равно нулю. Для любого другого перечислителя, определение которого не имеет инициализатора, соответствующим значением является значение предыдущего перечислителя плюс единица.
Перечисления в стиле C++11:
int main()
{
  enum class Color { Red, Green, Blue };
  Color c = Color::Blue;
}

Еще пример:

enum Color { red, green, blue };
Color r = red;
switch(r)
{
    case red  : std::cout << "red\n";   break;
    case green: std::cout << "green\n"; break;
    case blue : std::cout << "blue\n";  break;
}
// int n = r; // ошибка: нет преобразования перечисления с областью для int
int n = static_cast<int>(r); // OK, n = 0

Преобразование типов с помощью static_cast

Пример 1:

char c = 97;
std::cout << static_cast<int>(c) << std::endl; // вывод 97, а не 'a'

Пример 2:

int i1 = 11;
int i2 = 3;
std::cout << i1/i2; // 3
float x = static_cast<float>(i1) / i2;  // вывод x = 3.66667
Кортежи
#include <iostream>
#include <tuple>
 
using namespace std;
 
int main()
{
    tuple<int, char, string> t{ 4, 'z', "C++" }; // 1 способ
    auto x = make_tuple(4, 'z', "C++"); // 2 способ
    auto s1 = get<2>(x);
    get<0>(x) = 5; 
    int i; char c; string s;
    tie(i, c, s) = x; // распаковка
    cout << get<0>(x) << get<1>(x) << get<2>(x); // 5zC++
    cout << i << c << s;// 5zC++
}

Лабораторные работы

Все задания, которые вы не успели выполнить на уроке, автоматически становятся вашим домашним заданием. Домашнее задание должно быть выполнено до следующего урока.

Правила оформления работ:

  • Для выполнения заданий необходимо использовать перечисления и оператор switch.
  • Все задания должны выполняться с помощью функций, результаты должны проверяться оператором assert в заголовочном файле.
  • Все функции и файлы должны сопровождаться комментариями с постановкой задания.
Лабораторная работа 1:

Выполнить: Создайте функцию (printDay), которая получает число
— день недели (от 1 до 7) и возвращает полное название соответствующего дня (если введено 1, то функция должна напечатать «Понедельник», если 2«Вторник» и т.д.)

Указание: Добавьте заголовочный файл в свой проект. Введите там объявление перечисления и сигнатуру вашего метода:

// тип перечисления для дня: MON для Monday и т.д.
enum Day {MON=1, TUE, WED, THE, FRI, SAT, SAN };
 
// выводит заданный день
void printDay(Day d);

Примерный вывод:

пожалуйста, введите номер дня недели:
>> 2
Вторник

[Solution and Project name: Lesson_4, file name L4Lab1Imp.cpp, L4Lab1main.cpp, L4Lab1header.h]

✍ Алгоритм:

  1. Откройте Microsoft Visual Studio. Создайте новый консольный проект, назовите свой проект Lesson_4. Среди дополнительных опций отметьте Пустой проект и ничего больше. Нажмите кнопку Готово.
  2. В окне обозревателя решений найдите папку с исходными файлами, щелкните по ней правой кнопкой мыши и выберите Добавить -> Создать элемент. Мы собираемся создать два cpp-файла. Назовите их так, как написано в задании к работе.
  3. В окне обозревателя решений найдите папку заголовочных файлов, щелкните по ней правой кнопкой мыши и выберите Добавить -> Создать элемент. Мы собираемся создать заголовочный файл .h. Дайте ему название, как указано в задании к работе.
  4. Сначала давайте определим перечисление для хранения названий дней недели. Определение должно быть размещено в заголовочном файле. Откройте заголовочный файл и добавьте код:
  5. #ifndef L4LAB1HEADER_H
    #define L4LAB1HEADER_H
    //тип для представления дня недели
    enum Day { MON = 1, TUE, WED, THE, FRI, SAT, SAN };
    
    #endif L4LAB1HEADER_H
    
  6. Добавьте определение нашей функции printDay(). Она должна принимать один параметр – номер дня недели (тип параметра — Day — перечисление). Определение функции также должно быть помещено в заголовочный файл:
  7. // выводит заданный день в стандартный вывод
    void printDay(Day);
    
  8. Откройте код L4Lab1Imp.cpp, мы собираемся создать реализацию нашей функции. Переключитесь на заголовочный файл и добавьте пространство имен std:
  9. #include <iostream>
    #include <cassert>
    #include "L4Lab1header.h"
    using namespace std;
    
  10. Добавьте сигнатуру вашей функции:
  11. // выводит заданный день в стандартный вывод
    void print_month(Day d) {
      // ...
    }
    
  12. Чтобы проверить номер дня, нам нужно использовать оператор Switch. Добавьте код внутри области действия функции:
  13. switch (d)
    	{
    	case 1:
    		std::cout << "Monday" << std::endl;
    		break;
    	case 2:
    		std::cout << "Tuesday" << std::endl;
    		break;
    	case 3:
    		std::cout << "Wednesday" << std::endl;
    		break;
    	case 4:
    		std::cout << "Thursday" << std::endl;
    		break;
    	case 5:
    		std::cout << "Friday" << std::endl;
    		break;
    	case 6:
    		std::cout << "Saturday" << std::endl;
    		break;
    	case 7:
    		std::cout << "Sunday" << std::endl;
    		break;
    	}
    
  14. Откройте L4Lab1main.cpp. Подключите заголовочный файл и необходимые библиотеки:
  15. #include <iostream>
    #include <cassert>
    #include "L4Lab1header.h"
    using namespace std;
    
  16. В теле функции main() попросите пользователя ввести целое число и присвоить значение переменной dayNumb.
  17. int dayNumb;
    cout << "пожалуйста, введите номер дня недели:";
    cin >> dayNumb;
    
  18. Чтобы вызвать функцию, нам нужно передать ей один параметр типа перечисления (тип Day). Но все, что у нас есть, — это переменная dayNumb целочисленного типа. Мы можем использовать static_cast для преобразования переменной в тип Day:
  19. Day d;
    d = static_cast<Day>(dayNumb);
    
  20. Теперь мы можем вызвать функцию:
  21. printDay(d);
    
  22. Запустите программу и проверьте выходные данные.
Задание 1:

Выполнить: Определите тип данных перечисления Month для представления месяцев.
Создайте функцию (printMonth()), которая будет выводить полное название месяца для переданного короткого названия месяца. Используйте оператор switch.

Указание 1: Создайте другую функцию (inc()), которая выводит следующий месяц для переданного короткого названия месяца.
Указание 2: Добавьте заголовочный файл. Внутри файла добавьте перечисление и объявление вашей функции:

// тип данных для представления месяца: JAN для января и т.д.
enum Month {JAN=1, FEB, MAR, /* TODO: ... */ DEC};
// выводит заданный месяц
void printMonth(Month m);
//возвращает следующий месяц
Month inc(Month m);

Указание 2: LПосмотрите на приведенный ниже код и разберитесь в нем (использование static_cast):

(m == DEC)? JAN: static_cast<Month>(m + 1);
// Тестирование функции:
 assert (JAN == inc (DEC));

Примерный вывод:

Полное название JUN: June
Следующий месяц после DEC: 1

[Solution and Project name: Lesson_4, file name L4Task1Imp.cpp, L4Task1main.cpp, L4Task1header.h]

Задание 2:

Выполнить: Для предыдущего задания создайте функцию ( dec()), которая для введенного месяца отображает предыдущий месяц.

Указание 1: Тестирование функции в main:

assert (JAN == dec (FEB));

Указание 2: Добавьте объявление в заголовочный файл:

// возвращает предыдущий месяц
Month dec(Month m);

Примерный вывод:

Полное название JUN : June
Предыдущий месяц перед JUN: 5

[Solution and Project name: Lesson_4, file name L4Task2Imp.cpp, L4Task2main.cpp, L4Task2header.h]

Задание 3:

Выполнить: {2 points} Создайте функцию логического типа, которая возвращает значение True (или 1), если год (положительное целое число) является високосным, и значение False (или 0) в противном случае.

Указание 1: Високосный год — это год, который делится на 4, за исключением тех лет, которые делятся на 100 и не делятся на 400.

Указание 2: Добавьте несколько тестов в основную функцию. 2000 и 2012 годы — високосные, 2100-й — обычный год.

Указание 3: Добавьте объявление в заголовочный файл:

// проверяет високосный ли год
bool is_leap(int);

Примерный вывод:

Введите год: 2000
это високосный год - 1

[Solution and Project name: Lesson_4, file name L4Task3Imp.cpp, L4Task3main.cpp, L4Task3header.h]

Задание 4: Кортежи

Выполнить: В базе хранится информация о количестве разных оценок группы в виде кортежа: <оценка, количество>. Сначала запросить количество разных оценок, а затем вывести отдельно все оценки и их количество, используя распаковку кортежа.

Примерный вывод:

Введите количество оценок 2, 3, 4, 5: 
>> 3 >> 5 >> 10 >> 4
двойки = 3
тройки = 5
четверки = 10
пятерки = 4

[Solution and Project name: Lesson_4, file name L4Task4Imp.cpp, L4Task4main.cpp, L4Task4header.h]