Skip to content

DaniilZ77/cppio

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Лабораторная №10 (WW_cpp_io)

Содержание

  1. Содержание
  2. Задание
    1. Комментарии к заданию
  3. Требования к корректности решения
    1. Стандартные требования
    2. Детали реализации
    3. Формат бинарных файлов
    4. Вспомогательные манипуляторы
    5. Формат вывода списка
    6. Консольное приложение
    7. Структура репозитория
  4. Сроки сдачи
  5. Система оценки

Задание

Вам требуется реализовать консольное приложение ./lab-10_cppio, которое хранит упорядоченный список сотрудников некой компании. Приложение позволяет просматривать существующий штат из разработчиков и продавцов, добавлять новых сотрудников, а также сохранять и загружать список в файл в бинарном виде.

Вам потребуется:

  • Дописать реализации классов Developer (сотрудник-разработчик) и SalesManager (сотрудник-продавец) в include/employees.h и соответствующем .cpp-файле. Эти классы уже хранят все необходимые данные и корректно рассчитывают зарплату при помощи метода salary().
  • Вынести общие для всех сотрудников логику, интерфейс и данные в базовый класс Employee. Проектируйте класс Employee с учётом того, что в будущем могут быть добавлены новые должности.
  • Реализовать класс EmployeeArray, хранящий гетерогенный массив сотрудников (массив, в котором могут быть сотрудники разных типов).

Ввод/вывод наследников Employee, а также класса EmployeeArray должен быть реализован в стиле C++:

  • std::ostream& operator<<(std::ostream&, const Employee&); выводит текстовое описание сотрудника произвольного типа. Используется в команде list через operator<<(std::ostream&, const EmployeeArray&).
  • std::istream& operator>>(std::istream&, Employee&); считывает свойства сотрудника конкретного типа (неизвестного на этапе компиляции). Используется в команде add.
  • std::ofstream& operator<<(std::ofstream&, const Employee&); выводит бинарное представление сотрудника произвольного типа, включая пометку о типе сотрудника. Используется в команде load.
  • std::ifstream& operator>>(std::ifstream&, Employee&); считывает бинарное представление сотрудника конкретного типа (неизвестного на этапе компиляции), не включая пометку о типе сотрудника. Используется в команде save.

Для этого вам потребуются виртуальные методы в классе Employee и наследниках.

Для упрощения работы с бинарным представлением также реализуйте собственные манипуляторы в отдельных файлах bin_manip.h и bin_manip.cpp.

Комментарии к заданию

Разрешается использовать std::vector/std::string для упрощения кода, в том числе как поля.

В этом задании не очень хорошо:

  • То, что вывел operator<<, нельзя сразу считать при помощи operator>>. Нарушается симметрия.
  • Разделение текстового/бинарного формата происходит в зависимости от типа потока. Это неочевидно и усложняет автотесты. Нельзя записать бинарно в std::stringstream или записать текст в файл (например, для отладки).

Не забудьте:

  • добавить/запретить конструкторы, деструкторы, конструкторы копирования и операторы присваивания, если это необходимо;
  • переопределить операторы ввода/вывода с корректной обработкой ошибок;
  • добавить virtual куда нужно;
  • добавить friend куда нужно.

Требования к корректности решения

Стандартные требования

Смотри стандартные требования из предыдущих заданий (они теперь доступны в общей папке), название папки и файла — lab-10_cppio.

Новое требование: всё, кроме main, должно лежать в каком-нибудь пространстве имён; обязательно использовать анонимные пространства имён, где разумно.

Детали реализации

  • Объект-сотрудник владеет C-style строчкой с именем.
  • Экземпляр класса EmployeeArray владеет всеми своими сотрудниками.
  • Назначение полей (может немного измениться после выделения базового класса Employee):
    • Developer: имя _name, базовая зарплата _base_salary, наличие бонуса _has_bonus.
    • SalesManager: имя _name, базовая зарплата _base_salary, количество совершённых продаж _sold_nm, выручка с одной продажи _price.
  • Все операторы ввода-вывода и вспомогательные манипуляторы должны корректно обрабатывать ошибки и сигнализировать о них. Например, если read_c_str не нашёл нулевой символ до конца файла, это ошибка формата ввода.

Формат бинарных файлов

  • Все целые числа записываются в файл как четыре байта в порядке little-endian (от младших к старшим). Все числа знаковые, но от 0 до 2^31-1.
  • Все булевские значения записываются как один байт: 0 соответствует false, 1 соответствует true.
  • Строчки записываются в бинарный файл в стиле Си: байты строчки, за которыми следует один нулевой байт.

Бинарный файл содержит один объект EmployeeArray в следующем формате:

<число сотрудников, int32><сотрудник 1>...<coтрудник N>

В начале каждого сотрудника идёт одно число — его тип, после чего набор полей, специфичный для типа:

  • Формат Developer:
    <тип := 1, int32><имя, c-string><оклад; int32><наличие премии; bool, 1 байт>
    
  • Формат SalesManager:
    <тип := 2, int32><имя, c-string><оклад, int32><совершено продаж, int32><выручка с одной продажи, int32>
    

Вспомогательные манипуляторы

Для бинарного ввода-вывода реализуйте и используйте вспомогательные манипуляторы, а не работайте с байтами каждый раз заново.

Манипуляторы должны позволять читать и записывать в произвольные потоки (необязательно файловые) бинарные данные. Примеры кода ниже должны компилироваться и корректно работать.

Ввод-вывод знаковых 32-битных little endian чисел (тип std::int32_t из заголовка <cstdint>), отрицательные числа не поддерживаются:

std::stringstream s;
int x = 10;
s << write_le_int32(x);  // Теперь в s лежит четыре байта: 0A 00 00 00.
s >> read_le_int32(x);  // Обратная операция: присваивает x = 10.
s.write("\x12\x34\x56\0", 4);
s >> read_le_int32(x);  // x = 0x00563412 = 5649426

Ввод-вывод булевских значений (тип bool):

std::stringstream s;
bool y = true;
s << write_bool(y);  // Теперь в s лежит один байт: 0 (false) или 1 (true).
s >> read_bool(y);  // Симметрично: присваивает y = true.

Манипуляторы для ввода-вывода строк в стиле Си (тип char*):

char z[10] = "Hm";
s << write_c_str(z);  // Теперь в s лежит 3 байта: 48 6D 00
s >> read_c_str(z, sizeof z);  // Симметрично: считывает строку в стиле C (с завершающим нулём) и
                               // записывает в буфер z определённого размера.
                               // Если строка не помещается — ошибка формата.
s.write("Hello", 6);
s >> read_c_str(z, sizeof z);
assert(!strcmp("Hello", z));

Формат вывода списка

Приложению требуется уметь по команде list выводить информацию об N хранящихся сотрудниках в следующем виде:

1. <Должность сотрудника 1>
<информация о сотруднике 1>
2. <Должность сотрудника 2>
<информация о сотруднике 2>
...
N. <Должность сотрудника N>
<информация о сотруднике N>
== Total salary: <суммарная заработная плата всех сотрудников>
<пустая строка>

Обратите внимание на дополнительную пустую строку после конца списка.

  • Для разработчика:
    • Должность: Developer
    • Информация:
      Name: <имя>
      Base Salary: <базовая зарплата>
      Has bonus: <наличие бонуса, один символ, плюс или минус>
      
  • Для продавца:
    • Должность: Sales Manager
    • Информация:
      Name: <имя>
      Base Salary: <базовая зарплата>
      Sold items: <количество продаж>
      Item price: <выручка с одной продажи>
      

Консольное приложение

Приложение запускается следующей командой:

./lab-10_cppio

В процессе работы программа хранит в памяти список сотрудников, считывает команды из stdin и выводит результат в stdout (в стиле C++). Каждая команда занимает одну строчку:

  • exit — завершение работы приложения, аналогично концу stdin.
  • load <file-name>добавить в конец текущего списка данные из файла, см. формат бинарных файлов.
  • save <file-name> — сохранить текущий список в файл, см. формат бинарных файлов.
  • add <type> <args>* — добавить сотрудника. Здесь <type> — это число-тип сотрудника (как в формате бинарных файлов), а <args>* — специфичные для типа параметры:
    • Для разработчика (<type>=1): имя, базовая зарплата, наличие бонуса (0 или 1).
    • Для продавца (<type>=2): имя, базовая зарплата, количество совершённых продаж, выручка с одной продажи.
  • list — вывести текущий список сотрудников, см. формат вывода списка.

Ограничения:

  • Все команды корректны, числа в текстовом формате записываются в обычном десятичном виде.
  • Имена сотрудников не длиннее 100 символов и состоят из латинских букв, цифр, знаков дефиса и нижнего подчёркивания.
  • Имена могут совпадать.
  • Все числа-параметры сотрудников неотрицательны и не превосходят 10^9.
  • Общая зарплата всех сотрудников в списке не превосходит 10^9.

Пример запуска приложения:

> ./lab-10_cppio
add 2 Joe 100 20 300
add 1 Billy 1000 1
list
1. Sales Manager
Name: Joe
Base Salary: 100
Sold items: 20
Item price: 300
2. Developer
Name: Billy
Base Salary: 1000
Has bonus: +
== Total salary: 2160

save example.edb
add 1 Bobby 500 0
load example.edb
list
1. Sales Manager
Name: Joe
Base Salary: 100
Sold items: 20
Item price: 300
2. Developer
Name: Billy
Base Salary: 1000
Has bonus: +
3. Developer
Name: Bobby
Base Salary: 500
Has bonus: -
4. Sales Manager
Name: Joe
Base Salary: 100
Sold items: 20
Item price: 300
5. Developer
Name: Billy
Base Salary: 1000
Has bonus: +
== Total salary: 4820

save merged.edb
exit
> hexdump -C merged.edb
00000000  05 00 00 00 02 00 00 00  4a 6f 65 00 64 00 00 00  |........Joe.d...|
00000010  14 00 00 00 2c 01 00 00  01 00 00 00 42 69 6c 6c  |....,.......Bill|
00000020  79 00 e8 03 00 00 01 01  00 00 00 42 6f 62 62 79  |y..........Bobby|
00000030  00 f4 01 00 00 00 02 00  00 00 4a 6f 65 00 64 00  |..........Joe.d.|
00000040  00 00 14 00 00 00 2c 01  00 00 01 00 00 00 42 69  |......,.......Bi|
00000050  6c 6c 79 00 e8 03 00 00  01                       |lly......|
00000059

Структура репозитория

<корень-личного-репозитория>
|--lab-10_cppio
   |--include
   |  |-- bin_manip.h
   |  |-- employees.h
   |--src
   |  |-- bin_manip.cpp
   |  |-- employees.cpp
   |  |-- main.cpp
   |--Makefile

Папку obj, объектные и исполняемые файлы класть в репозиторий не разрешается.

Сроки сдачи

Уточняйте у своего преподавателя.

Система оценки

  • Задание оценивается в 10 баллов: 7 за корректность и 3 за стиль.
  • Точные критерии оценки каждой из частей остаются на усмотрение преподавателя.

About

Лабораторная по вводу выводу на C++

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors