1

Тема: Як зберегти у файлі (файлах) об'єкти двох взаємозв'язаних класів?

Необхідно записати у файл об'єкти Worker (і, скоріше за все Department): (взаємозв'язок класів у темі - http://replace.org.ua/topic/6347/, як покращити - не знаю, згідно завдання може і ніяк)

class Person
{
protected:
    string surname;
    string name;
    string birthday;
    string city;
    string street;
    int house_number;
    int flat_number;
    string phone_number;
    string education;
};

class Worker: public Person
{
    int account_number_salary;
    Department department;
    Position position;
    Project projects[NUMBER_LAST_PROJECTS];
    int current_number_projects;
    double experience;
    double total_projects_cost;
};

class Department
{
    string name;
    Worker *workers;
    int number_workers;
    string major_department_name;
    double amount_prize;
    string *positions;
    int number_positions;
};

В попередньому варіанті задачі я зробила ось так:

Прихований текст
/* Предметна область - відділ кадрів фірми.
Розв'язувані задачі - облік співробітників. Реалізувати наступні сервіси:

-Заповнення бази даних
-Перегляд даних про всіх співробітників
-Доповнення бази даних новим співробітником
-Видалення із бази даних вказаного співробітника
-Упорядкування: співробітники по відділах, по посадах
-Пошук: всі дані про співробітника з певним ПІБ; як подзвонити співробітникові УУ
-Вибірка: співробітники відділу NN
-Обчислення: кількість співробітників у відділі NN; фонд заробітної плати по відділах
-Корекція: видалення зведень про звільненого співробітника;
переведення співробітника з відділу ХХ у відділ УУ
-Табличний звіт: список співробітників по відділах, підсумок - фонд зарплати кожного відділу
і загальний фонд по фірмі

Додаткові вимоги: ПІБ співробітника не повинні бути порожніми значеннями, а табельний номер співробітника
повинний бути унікальним.
Для обробки даних скористатися динамічним масивом покажчиків на структури відповідного типу.  */

#include <iostream>
#include <iomanip>
#include <fstream>
#include <windows.h>
#include <string>
#include <conio.h>

using namespace std;


struct PersonalInfo
{
    string surname;
    string name;
    string birthday;
    struct Adress
    {
        string city;
        string street;
        int house_number;
        int flat_number;
    } adress;
    string phone_number;
    string education;
};

struct Worker
{
    int ID;
    PersonalInfo personal;
    string department_name;
    string position;
    int salary;
    int experience;
    string work_status;
};

struct Department
{
    string dep_name;
    int funds;
    Worker *workers;
    int number_workers;
};

// Log info for easy debug
void log(string message)
{
    ofstream f("hr_department.log", ios::out | ios::app);
    f << message << "\n";
    f.close();
}


void createDepartments(Department *&departments, int &number_departments)
{
    if (number_departments == 0)
        number_departments = 1;
    departments = new Department[number_departments];
}

void addDepartment(Department *&departments, int &number_departments, string name_departments)
{
    if (departments == NULL)
    {
        createDepartments(departments, number_departments);
        departments[number_departments - 1].dep_name = name_departments;
        for (int i = 0; i < number_departments; ++i)
        {
            departments[i].number_workers = 1;
            for (int j = 0; j < departments[i].number_workers; ++j)
                departments[i].workers = new Worker[departments[i].number_workers];
        }
    }
    else
    {
        Department *new_departments = new Department[number_departments + 1];

        for (int i = 0; i < number_departments; ++i)
            new_departments[i] = departments[i];

        new_departments[number_departments].dep_name = name_departments;

        if (departments != NULL)
            delete[]departments;

        departments = new_departments;
        ++number_departments;
    }
}

void addWorkerInDepartment(Department *&departments, int &number_departments, Worker worker)
{ 
    if (departments == NULL)
    {
        addDepartment(departments, number_departments, worker.department_name);
        departments[number_departments - 1].workers[departments[number_departments - 1].number_workers - 1] = worker;
    }
    else
    {
        int i = 0;
        while (i < number_departments && departments[i].dep_name != worker.department_name)
            ++i;
        if (i < number_departments)
        {
            Worker *temp_workers = new Worker[departments[i].number_workers + 1];
            for (int j = 0; j < departments[i].number_workers; ++j)
                temp_workers[j] = departments[i].workers[j];
            temp_workers[departments[i].number_workers] = worker;
            delete[]departments[i].workers;
            departments[i].workers = temp_workers;
            ++departments[i].number_workers;
        }
        else
        {
            addDepartment(departments, number_departments, worker.department_name);
            departments[i].number_workers = 1;
            departments[i].workers = new Worker[departments[i].number_workers];
            departments[i].workers[departments[i].number_workers - 1] = worker;
        }

    }
}

void deleteWorkerFromTheDepartment(Department *&departments, int &number_departments, Worker worker)
{
    if (departments == NULL)
        cout << "Database is empty\n";
     else
    {
        int i = 0;
        while (i < number_departments && departments[i].dep_name != worker.department_name)
            ++i;
        if (i < number_departments)
        {
            int k = 0;
            while (k < departments[i].number_workers && departments[i].workers[k].ID != worker.ID)
                ++k;
           
            if (k < departments[i].number_workers)
            {
                Worker *temp_workers = new Worker[departments[i].number_workers - 1];
                for (int j = 0; j < k; ++j)
                    temp_workers[j] = departments[i].workers[j];
                for (int j = k; j < departments[i].number_workers - 1; ++j)
                    temp_workers[j] = departments[i].workers[j + 1];
                
                delete[]departments[i].workers;
                departments[i].workers = temp_workers;
                --departments[i].number_workers;
            }
        }
    }
}

bool SetWindow(int Width, int Height)
{
    _COORD coord;
    coord.X = Width;
    coord.Y = Height;

    _SMALL_RECT Rect;
    Rect.Top = 0;
    Rect.Left = 0;
    Rect.Bottom = Height - 1;
    Rect.Right = Width - 1;

    // Get handle of the standard output
    HANDLE Handle = GetStdHandle(STD_OUTPUT_HANDLE);
    if (Handle == NULL)
    {
        cout << "Failure in getting the handle\n" << GetLastError();
        return FALSE;
    }

    // Set screen buffer size to that specified in coord
    if (!SetConsoleScreenBufferSize(Handle, coord))
    {
        cout << "Failure in setting buffer size\n" << GetLastError();
        return FALSE;
    }

    // Set the window size to that specified in Rect
    if (!SetConsoleWindowInfo(Handle, TRUE, &Rect))
    {
        cout << "Failure in setting window size\n" << GetLastError();
        return FALSE;
    }

    return TRUE;
}

struct ITEM{
    int x;
    int y;
    string name_menu;
};

// global variable
enum key { UP = 72, DOWN = 80, ENTER = 13, ESCAPE = 27 };
HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_SCREEN_BUFFER_INFO csbInfo;
SMALL_RECT consolRect;

COORD curspos = { 0, 1 };
WORD workWindowAttributes = 95;
WORD inactiveItemAttributes = 71;
WORD activeItemAttributes = 207;

void gotoxy(int x, int y)
{
    COORD cursorPos = { x, y };
    SetConsoleCursorPosition(hStdOut, cursorPos);
    SetConsoleCursorPosition(hStdOut, { x, y });
}

void getCursorPosition()
{
    GetConsoleScreenBufferInfo(hStdOut, &csbInfo);
    curspos = csbInfo.dwCursorPosition;
}

void showCursor(bool visible)
{
    CONSOLE_CURSOR_INFO ccInfo;
    ccInfo.bVisible = visible;
    ccInfo.dwSize = 20;
    SetConsoleCursorInfo(hStdOut, &ccInfo);
}

//TODO: color text, move to keys in the menu

void writeToFile(string file_name, Worker *workers, int number_workers)
{
    ofstream f_out(file_name, ios_base::out | ios_base::binary);
    if (!f_out)
        cout << "Can not open file to write\n";

    f_out.write((char *)&number_workers, sizeof(number_workers));
    for (int i = 0; i < number_workers; ++i)
    {
        int ser = workers[i].salary;
        f_out.write((char *)&ser, sizeof(ser));

        ser = workers[i].personal.adress.house_number;
        f_out.write((char *)&ser, sizeof(ser));

        ser = workers[i].personal.adress.flat_number;
        f_out.write((char *)&ser, sizeof(ser));

        ser = workers[i].experience;
        f_out.write((char *)&ser, sizeof(ser));

        ser = workers[i].personal.surname.length();
        f_out.write((char *)&ser, sizeof(ser));
        f_out.write(workers[i].personal.surname.c_str(), ser);

        ser = workers[i].personal.name.length();
        f_out.write((char *)&ser, sizeof(ser));
        f_out.write(workers[i].personal.name.c_str(), ser);

        ser = workers[i].personal.birthday.length();
        f_out.write((char *)&ser, sizeof(ser));
        f_out.write(workers[i].personal.birthday.c_str(), ser);

        ser = workers[i].personal.phone_number.length();
        f_out.write((char *)&ser, sizeof(ser));
        f_out.write(workers[i].personal.phone_number.c_str(), ser);

        ser = workers[i].personal.education.length();
        f_out.write((char *)&ser, sizeof(ser));
        f_out.write(workers[i].personal.education.c_str(), ser);

        ser = workers[i].personal.adress.city.length();
        f_out.write((char *)&ser, sizeof(ser));
        f_out.write(workers[i].personal.adress.city.c_str(), ser);

        ser = workers[i].personal.adress.street.length();
        f_out.write((char *)&ser, sizeof(ser));
        f_out.write(workers[i].personal.adress.street.c_str(), ser);

        ser = workers[i].ID;
        f_out.write((char *)&ser, sizeof(ser));

        ser = workers[i].department_name.length();
        f_out.write((char *)&ser, sizeof(ser));
        f_out.write(workers[i].department_name.c_str(), ser);

        ser = workers[i].position.length();
        f_out.write((char *)&ser, sizeof(ser));
        f_out.write(workers[i].position.c_str(), ser);

        ser = workers[i].work_status.length();
        f_out.write((char *)&ser, sizeof(ser));
        f_out.write(workers[i].work_status.c_str(), ser);

    }
    cout << "Data is written in the file successfully\n";
    f_out.close();
}

void loadFromFile(string file_name, Worker *&workers, int &number_workers, Department *&departments, int &number_departments)
{
    ifstream f_in(file_name, ios_base::binary);

    if (!f_in)
        cout << "Can not open file to read\n";
    else
    { 
        f_in.read((char *)&number_workers, sizeof(number_workers));
        Worker *new_workers = new Worker[number_workers];
        char *temp_str;
        int ser;
        for (int i = 0; i < number_workers; ++i)
        {
            f_in.read((char *)&ser, sizeof(ser));
            new_workers[i].salary = ser;

            f_in.read((char *)&ser, sizeof(ser));
            new_workers[i].personal.adress.house_number = ser;

            f_in.read((char *)&ser, sizeof(ser));
            new_workers[i].personal.adress.flat_number = ser;
            
            f_in.read((char *)&ser, sizeof(ser));
            new_workers[i].experience = ser;          

            f_in.read((char *)&ser, sizeof(ser));
            temp_str = new char[ser + 1];
            memset(temp_str, 0, ser + 1);
            f_in.read(temp_str, ser);
            new_workers[i].personal.surname.assign(temp_str);
            delete[]temp_str;

            f_in.read((char *)&ser, sizeof(ser));
            temp_str = new char[ser + 1];
            memset(temp_str, 0, ser + 1);
            f_in.read(temp_str, ser);
            new_workers[i].personal.name.assign(temp_str);
            delete[]temp_str;

            f_in.read((char *)&ser, sizeof(ser));
            temp_str = new char[ser + 1];
            memset(temp_str, 0, ser + 1);
            f_in.read(temp_str, ser);
            new_workers[i].personal.birthday.assign(temp_str);
            delete[]temp_str;

            f_in.read((char *)&ser, sizeof(ser));
            temp_str = new char[ser + 1];
            memset(temp_str, 0, ser + 1);
            f_in.read(temp_str, ser);
            new_workers[i].personal.phone_number.assign(temp_str);
            delete[]temp_str;
            
            f_in.read((char *)&ser, sizeof(ser));
            temp_str = new char[ser + 1];
            memset(temp_str, 0, ser + 1);
            f_in.read(temp_str, ser);
            new_workers[i].personal.education.assign(temp_str);
            delete[]temp_str;
            
            f_in.read((char *)&ser, sizeof(ser));
            temp_str = new char[ser + 1];
            memset(temp_str, 0, ser + 1);
            f_in.read(temp_str, ser);
            new_workers[i].personal.adress.city.assign(temp_str);
            delete[]temp_str;
            
            f_in.read((char *)&ser, sizeof(ser));
            temp_str = new char[ser + 1];
            memset(temp_str, 0, ser + 1);
            f_in.read(temp_str, ser);
            new_workers[i].personal.adress.street.assign(temp_str);
            delete[]temp_str;
            
            f_in.read((char *)&ser, sizeof(ser));
            new_workers[i].ID = ser;
                      
            f_in.read((char *)&ser, sizeof(ser));
            temp_str = new char[ser + 1];
            memset(temp_str, 0, ser + 1);
            f_in.read(temp_str, ser);
            new_workers[i].department_name.assign(temp_str);
            delete[]temp_str;
            
            f_in.read((char *)&ser, sizeof(ser));
            temp_str = new char[ser + 1];
            memset(temp_str, 0, ser + 1);
            f_in.read(temp_str, ser);
            new_workers[i].position.assign(temp_str);
            delete[]temp_str;
            
            f_in.read((char *)&ser, sizeof(ser));
            temp_str = new char[ser + 1];
            memset(temp_str, 0, ser + 1);
            f_in.read(temp_str, ser);
            new_workers[i].work_status.assign(temp_str);
            delete[]temp_str;

            addWorkerInDepartment(departments, number_departments, new_workers[i]);
        }
            workers = new_workers;
            cout << "Data loaded successfully\n";
    }
    
    f_in.close();
}

bool validInputPhoneNumber(const string phone)
{
    int i = 0;
    int phone_length = phone.length();
    while (i < phone_length)
    {
        if (!(isdigit(phone[i]) || phone[i] == '-'))
            return false;
        ++i;
    }
    return true;
}

bool validInputNameSurname(const string name)
{
    if (name == " ")
        return false;
    int i = 0;
    int name_length = name.length();
    while (i < name_length)
    {
        if (!(isalpha(name[i])))
            return false;
        ++i;
    }
    return true;

}

bool validInputString(const string str)
{
    if (str == " ")
        return false;
    return true;
}

bool validInputNumber(const int records)
{
    if (records >= 1)
        return true;
    else
        return false;
}

void getDayMonthYear(string str, int &day, int &month, int &year)
{
    int pos_day = str.find('.');

    if (pos_day != string::npos)
        for (int i = 0; i < pos_day; ++i)
            day = stoi(str);

    int pos_month = str.find('.', pos_day + 1);
    if (pos_month != string::npos)
        for (int i = pos_day + 1; i < pos_month; ++i)
            month = stoi(str);

    int length = str.length();
    for (int i = pos_month + 1; i <length; ++i)
        year = stoi(str);
}

bool isLeapYear(unsigned int year)
{
    return !(year % 400) || (!(year % 4) && (year % 100));
}

bool validBirthday(string str)
{
    if (str == "")
        return false;

    int i = 0;
    int length = str.length();
    while (i < length)
    {
        if (!(isdigit(str[i]) || '.'))
            return false;
        ++i;
    }
    
    int day, month, year;
    getDayMonthYear(str, day, month, year);
    
    if (year < 1 || month < 1 || day < 1)
        return false;

    if (month == 2)
    {
        if (isLeapYear(year))
        {
            if (day <= 29)
                return true;
        }
        else if (day <= 28)
            return true;
    }

    switch (month)
    {
    case 1: case 3: case 5: case 7: case 8: case 10: case 12:
        if (day <= 31)
            return true;
        break;
    case 4: case 6: case 9: case 11:
        if (day <= 30)
            return true;
        break;
    }

    return false;
}

//TODO: VALID BIRTHDAY

void inputWorkerRecord(Worker &worker, int index)
{
    cin.ignore(255, '\n');

    do{
        cout << "Enter surname: ";
        getline(cin, worker.personal.surname);
    } while (!validInputNameSurname(worker.personal.surname));

    do{
        cout << "Enter name: ";
        getline(cin, worker.personal.name);
    } while (!validInputNameSurname(worker.personal.name));

    
    do{
        cout << "Enter birthday (dd.mm.yyyy): ";
        getline(cin, worker.personal.birthday);
    } while (!validBirthday(worker.personal.birthday));

    do{
        cout << "Enter city: ";
        getline(cin, worker.personal.adress.city);
    } while (!validInputString(worker.personal.adress.city));

    do{
        cout << "Enter street: ";
        getline(cin, worker.personal.adress.street);
    } while (!validInputString(worker.personal.adress.street));

    do{
        cout << "Enter the house number: ";
        cin >> worker.personal.adress.house_number;
    } while (!worker.personal.adress.house_number);

    do{
        cout << "Enter the flat number: ";
        cin >> worker.personal.adress.flat_number;
    } while (!worker.personal.adress.flat_number);

    cin.ignore(255, '\n');

    do{
        cout << "Enter phone number: ";
        getline(cin, worker.personal.phone_number);
    } while (!validInputPhoneNumber(worker.personal.phone_number));

    do{
        cout << "Enter education: ";
        getline(cin, worker.personal.education);
    } while (!validInputString(worker.personal.education));

    do{
        cout << "In which department works: ";
        getline(cin, worker.department_name);
    } while (!validInputString(worker.department_name));

    do{
        cout << "In which position: ";
        getline(cin, worker.position);
    } while (!validInputString(worker.position));

    do{
        cout << "What salary: ";
        cin >> worker.salary;
    } while (!validInputNumber(worker.salary));

    do{
        cout << "What experience: ";
        cin >> worker.experience;
    } while (!validInputNumber(worker.experience));

    cin.ignore(255, '\n');

    do{
        cout << "What is the status of work ( fired or work): ";
        getline(cin, worker.work_status);
    } while (!validInputString(worker.work_status));

    worker.ID = index +1;
}

Worker *createNewBaseWorker(int &number_workers, Department *&departments, int &number_departments)
{
    cout << "Enter the number of workers: ";
    cin >> number_workers;

    if (number_workers == 0)
        number_workers = 1;

    Worker *temp = new Worker[number_workers];
    for (int i = 0; i < number_workers; ++i)
    {
        inputWorkerRecord(temp[i], i);
        addWorkerInDepartment(departments, number_departments, temp[i]);
    }

    return temp;
}

int maxID(const Worker *workers, int &number_workers)
{
    int max = workers[0].ID;
    for (int i = 1; i < number_workers; ++i)
        if (workers[i].ID > max)
            max = workers[i].ID;

    return max;
}

void addRecord(Worker *&workers, int &number_workers, Department *&departments, int &number_departments)
{
    if (workers == NULL)
        workers = createNewBaseWorker(number_workers, departments, number_departments);
    else
    {
        Worker *new_workers = new Worker[number_workers + 1];
        for (int i = 0; i < number_workers; ++i)
            new_workers[i] = workers[i];
        delete[]workers;
        workers = new_workers;
        inputWorkerRecord(workers[number_workers], maxID(workers, number_workers));
        addWorkerInDepartment(departments, number_departments, workers[number_workers]);
        ++number_workers;
    }
}

void headPrintRecord()
{
    cout << "ID" << setw(8) << "Name " << setw(10) << "Surname " << setw(11) << "Birthday"<< setw(15) << "Phone number" << setw(8);
    cout << "City" << setw(12) << "Street" << setw(9) << "House" << setw(8) << "Flat" << setw(8);
    cout << "Depart." << setw(10) << "Position" << setw(8) << "Exper." << setw(8) << "Salary" << setw(15) << "Work status\n";
    cout << "----------------------------------------------------------------------------------------------------------------------------------\n";
}

void printRecord(const Worker worker)
{
    cout << worker.ID << setw(10) << worker.personal.name << setw(11) << worker.personal.surname << setw(9) << worker.personal.birthday << setw(15) << worker.personal.phone_number << setw(10);
    cout << worker.personal.adress.city << setw(12) << worker.personal.adress.street << setw(8) << worker.personal.adress.house_number << setw(6) << worker.personal.adress.flat_number << setw(10);
    cout << worker.department_name << setw(10) << worker.position << setw(8) << worker.experience << setw(8) << worker.salary << setw(10) << worker.work_status << "\n";
}

void showAllWorkers(const Worker *workers, int number_workers)
{
    if (workers == NULL)
        cout << "Database is empty\n";
    else
    {
        headPrintRecord();
        for (int i = 0; i < number_workers; ++i)
        {
            cout << workers[i].ID << setw(10) << workers[i].personal.name << setw(11) << workers[i].personal.surname  << setw(9)<< workers[i].personal.birthday << setw(15) << workers[i].personal.phone_number << setw(10);
            cout << workers[i].personal.adress.city << setw(12) << workers[i].personal.adress.street << setw(8) << workers[i].personal.adress.house_number << setw(6) << workers[i].personal.adress.flat_number << setw(10);
            cout << workers[i].department_name << setw(10) << workers[i].position << setw(8) << workers[i].experience << setw(8) << workers[i].salary << setw(10) << workers[i].work_status << "\n";
        }
    }
}

void quit(bool &exit, Worker *workers, int number_workers)
{
    char save_choice;
    cout << "Save changes? (Y/N): ";
    cin >> save_choice;
    if (tolower(save_choice) == 'y')
    {
        string file_name;
        cout << "Enter file name to save: ";
        cin >> file_name;
        writeToFile(file_name, workers, number_workers);
    }

    char exit_choice;
    cout << "Are you sure you want to exit? (Y/N): ";
    cin >> exit_choice;
    if (tolower(exit_choice) == 'y')
    {
        cout << "Bye!\n";
        exit = true;
    }
}

void deleteRecord(Worker *&workers, int &number_workers, int pos_record, Department *&departments, int number_departments)
{
    if (workers == NULL)
        cout << "Database is empty\n";
    else
    {
        --pos_record;
        if (pos_record < 0 || pos_record >= number_workers)
            cout << "Database doesn't have any record with this number\n";
        else
        {
            Worker *new_workers = new Worker[number_workers - 1];
            for (int i = 0; i < pos_record; ++i)
                new_workers[i] = workers[i];
            for (int i = pos_record; i < number_workers - 1; ++i)
                new_workers[i] = workers[i + 1];
            deleteWorkerFromTheDepartment(departments, number_departments, workers[pos_record]);
            delete[]workers;
            workers = new_workers;
            --number_workers;
            cout << "\n\tWORKER DELETED SUCCESSFULLY\n";
        }
    }
}

void printOnlyPhoneNumber(const Worker worker)
{
    cout << "\tID" << setw(10) << "Name" << setw(15) << setw(15) << "Surname" << setw(15) << "Phone number\n";
    cout << "--------------------------------------------------------------------------------------------\n";
    cout << "\t" << worker.ID << setw(10) << worker.personal.name << setw(15) << worker.personal.surname << setw(15) << worker.personal.phone_number << "\n";
}

void searchRecordBySurname(const Worker *workers, int number_workers, string search_key, char mod = 'a')
{
    if (workers == NULL)
        cout << "Database is empty\n";
    bool search = false;
    for (int i = 0; i < number_workers; ++i)
    {
        if (workers[i].personal.surname == search_key)
        {
            if (mod == 'a')
                printRecord(workers[i]);
            else
                printOnlyPhoneNumber(workers[i]);
            search = true;
        }
    }
    if (!search)
        cout << "Not found " << search_key << "!\n";
}

void sortRecordByDepartmnets(Department *departments, int number_departments)
{
    if (departments != NULL)
    {
        int pos_min;
        string min;
        Department temp_department;

        for (int i = 0; i < number_departments - 1; i++)
        {
            pos_min = i;
            min = departments[i].dep_name;
            for (int j = 1 + i; j < number_departments; j++)
            {
                if (departments[j].dep_name < min)
                {
                    min = departments[j].dep_name;
                    pos_min = j;
                }
            }
            temp_department = departments[pos_min];
            departments[pos_min] = departments[i];
            departments[i] = temp_department;
        }

        for (int i = 0; i < number_departments; ++i)
        {
            if (departments[i].number_workers != 0)
            {
                headPrintRecord();
                for (int j = 0; j < departments[i].number_workers; ++j)
                    printRecord(departments[i].workers[j]);
                cout << "\n";
            }
        }
    }
    else
        cout << "Database is empty\n";
}

void sortRecordByPosition(Worker *workers, int number_workers)
{
    if (workers != NULL)
    {
        int pos_min;
        string min;
        Worker temp_worker;

        for (int i = 0; i < number_workers - 1; i++)
        {
            pos_min = i;
            min = workers[i].position;
            for (int j = 1 + i; j < number_workers; j++)
            {
                if (workers[j].position < min)
                {
                    min = workers[j].position;
                    pos_min = j;
                }
            }
            temp_worker = workers[pos_min];
            workers[pos_min] = workers[i];
            workers[i] = temp_worker;
        }

        showAllWorkers(workers, number_workers);
    }
    else
        cout << "Database is empty\n";
}


void selectByDepartments(string select_name_department, Department *departments, int number_departments)
{
    if (departments != NULL)
    {
        int i = 0;
        while (i < number_departments && departments[i].dep_name != select_name_department)
            ++i;

        if (i < number_departments)
            showAllWorkers(departments[i].workers, departments[i].number_workers);
        else
            cout << "This department does not exist\n";
    }
}

void calculateNumberWorkers(const Department *departments, int number_departments)
{
    if (departments == NULL)
        cout << "Database is empty\n";
    else
    {
        cout << "\nDepartment name " << setw(20) << "Number of workers\n";
        cout << "-------------------------------------------------\n";
        for (int i = 0; i < number_departments; ++i)
            cout << departments[i].dep_name << setw(20) << departments[i].number_workers << "\n";
    }
}

void calculateTotalFundsbyDepartment(Department *&departments, int number_departments)
{
    if (departments == NULL)
        cout << "Database is empty\n";
    else
    {
        for (int i = 0; i < number_departments; ++i)
        {
            departments[i].funds = 0;
            for (int j = 0; j < departments[i].number_workers; ++j)
                departments[i].funds += departments[i].workers[j].salary;
        }

        cout << "\nDepartment name " << setw(25) << "Total funds by department\n";
        cout << "-------------------------------------------------\n";
        for (int i = 0; i < number_departments; ++i)
            cout << departments[i].dep_name << setw(30) << departments[i].funds << "\n";
    }
}

void deleteInfoByFiredWorker(Worker *&workers, int &number_workers, Department *&departments, int number_departments)
{
    if (workers == NULL)
        cout << "Database is empty\n";
    else
    {
        char user_delete_answer;
        cout << "Do you want delete all fired workers? (Y/N): ";
        cin >> user_delete_answer;
        if (tolower(user_delete_answer) == 'y')
        {
            for (int i = 0; i < number_workers; ++i)
                if (workers[i].work_status == "fired")
                    deleteRecord(workers, number_workers, i + 1, departments, number_departments);
        }
        else
        {
            int delete_worker_ID;
            cout << "Enter ID worker that you want to delete: ";
            cin >> delete_worker_ID;
            int i = 0;
            while (i < number_workers && workers[i].ID != delete_worker_ID)
                ++i;
            if (i < number_workers)
            {
                if (workers[i].work_status == "fired")
                    deleteRecord(workers, number_workers, i + 1, departments, number_departments);
                else
                {
                    cout << "A worker with this ID not fired\n";
                    cout << "Are you sure that you want to remove information about him?(Y/N): ";
                    cin >> user_delete_answer;
                    if (tolower(user_delete_answer) == 'y')
                        deleteRecord(workers, number_workers, i + 1, departments, number_departments);
                }
            }
            else
                cout << "A worker with this ID does not exist!\n";
        }
    }
}

void staffMove(Worker &worker, Department *&departments, int &number_departments)
{
    if (departments == NULL)
        cout << "Database is empty\n";
    else
    {
        string name_department;
        cout << "Enter the name of the department which should to transfer a worker: ";
        cin >> name_department;
        deleteWorkerFromTheDepartment(departments, number_departments, worker);
        worker.department_name = name_department;
        addWorkerInDepartment(departments, number_departments, worker);
        cout << "WORKER MOVED SUCCESSFULLY\n";
    }
}

void listWorkerByDepartment(Department *departments, int number_department)
{
    if (departments == NULL)
        cout << "Database is empty\n";
    else
    {
        for (int i = 0; i < number_department; ++i)
        {
            cout << "\n\t----------------" << departments[i].dep_name << "------------------\n\n";
            headPrintRecord();
            for (int j = 0; j < departments[i].number_workers; ++j)
                printRecord(departments[i].workers[j]);
            cout << "\n";
        }
    }
}

void totalFunds(Department *departments, int number_department)
{
    if (departments == NULL)
        cout << "Database is empty\n";
    else
    {
        calculateTotalFundsbyDepartment(departments, number_department);
        int total_funds = 0;
        for (int i = 0; i < number_department; ++i)
            total_funds += departments[i].funds;
 
        cout << "--------------------------------------------------------\n";
        cout << "\n\tTOTAL FUNDS: " << total_funds << "\n";
    }

}
enum menuitems {CREATE_DATABASE, LOAD_FROM_FILE, SHOW_ALL, ADD_WORKER,
            DELETE_WORKER, SEARCH_BY_SURNAME, SORT_BY_DEPARTMENT, SORT_BY_POSITION,
            SELECT_BY_DEPARTMENT,CALCULATE_NUMBER_OF_WORKERS, CALCULATE_TOTAL_FUNDS_DEPARTMENT, DELETE_INFO_BY_FIRED_WORKER,
            STAFF_MOVE, LIST_WORKER_BY_DEPARTMENT, TOTAL_FUNDS, EXIT};

const int NUMBER_MENU = 17;

ITEM menu[NUMBER_MENU] = {
                            {30, 13, "CREATE DATABASE" },
                            {30, 15, "LOAD DATABASE FROM FILE" },
                            {30, 17, "SHOW ALL WORKERS" },
                            {30, 19, "ADD WORKER" },
                            {30, 21, "DELETE WORKER"},
                            {30, 23, "SEARCH WORKER BY SURNAME"},
                            {30, 25, "SORT BY DEPARTMENTS"},
                            {30, 27, "SORT BY POSITION" },
                            {30, 29, "SELECT BY DEPARTMENT" },
                            {30, 31, "CALCULATE: NUMBER OF WORKERS IN DEPARTEMENT"},
                            {30, 33, "CALCULATE: TOTAL FUNDS BY DEPARTMENT"},
                            {30, 35, "EDIT: DELETE INFO BY FIRED WORKER"},
                            {30, 37, "EDIT: STAFF MOVE"},
                            {30, 39, "REPORT: LIST WORKERS BY DEPARTMENT"},
                            {30, 41, "REPORT: TOTAL FUNDS"},
                            {30, 43, "EXIT" } };


void itemMenu(int sel, bool activate)
{
    WORD itemAttributes;
    if (activate)
        itemAttributes = activeItemAttributes;
    else
        itemAttributes = inactiveItemAttributes;
    gotoxy(menu[sel].x, menu[sel].y);
    SetConsoleTextAttribute(hStdOut, itemAttributes);
    cout << menu[sel].name_menu;
}

bool menuAction(int sel, Worker *&workers, int &number_workers, Department *&departments, int &number_departments)
{
    showCursor(true);
    int user_choice;
    bool exit = false;
    string load_file_name;
    string search_surname;
    string select_departments_name; 

        switch (sel)
        {
        case CREATE_DATABASE:
            system("cls");
            if (workers == NULL)
                cout << "\tYou create a new database!\n";
            else
            {
                char user_answer_choice;
                cout << "When you create a new database possible loss of data. Save an existing base? (Y/N): \n";
                cin >> user_answer_choice;
                if (tolower(user_answer_choice) == 'y')
                {
                    string save_file_name;
                    cout << "Enter file name to save: ";
                    cin >> save_file_name;
                    writeToFile(save_file_name, workers, number_workers);
                }
            }
            workers = createNewBaseWorker(number_workers, departments, number_departments);
            cout << "Database created successfully\n";
            break;
        case SHOW_ALL:
            system("cls");
            cout << "\n\nNUMBER WORKERS: " << number_workers << "\n\n";
            showAllWorkers(workers, number_workers);
            break;
        case ADD_WORKER:
            system("cls");
            addRecord(workers, number_workers, departments, number_departments);
            cout << "\n\tWORKER ADDED SUCCESSFULLY\n";
            break;
        case DELETE_WORKER:
            system("cls");
            int pos_delete_worker;
            if (workers != NULL)
            {
                cout << "Enter the number of worker to delete of base: ";
                cin >> pos_delete_worker;
            }
            deleteRecord(workers, number_workers, pos_delete_worker, departments, number_departments);
            break;
        case SEARCH_BY_SURNAME:
            system("cls");
            cout << "Enter a surname of worker to find of base: ";
            cin >> search_surname;
            char user_search_answer;
            cout << "Print all info of worker (a) or only phone number (p)?: ";
            cin >> user_search_answer;
            searchRecordBySurname(workers, number_workers, search_surname, user_search_answer);
            break;
        case SORT_BY_DEPARTMENT:
            system("cls");
            sortRecordByDepartmnets(departments, number_departments);
            break;
        case SORT_BY_POSITION:
            system("cls");
            sortRecordByPosition(workers, number_workers);
            break;
        case SELECT_BY_DEPARTMENT:
            system("cls");
            cout << "Enter a departments name to select: ";
            cin >> select_departments_name;
            selectByDepartments(select_departments_name, departments, number_departments);
            break;
        case LOAD_FROM_FILE:
            system("cls");
            if (workers != NULL)
            {
                char user_choice;
                cout << "You will lose your data! Continue?(Y/N)";
                cin >> user_choice;
                if (tolower(user_choice) == 'y')
                {
                    char user_answer_choice;
                    cout << "Save an existing base ? (Y / N): ";
                    cin >> user_answer_choice;
                    if (tolower(user_answer_choice) == 'y')
                    {
                        string save_file_name;
                        cout << "Enter file name to save: ";
                        cin >> save_file_name;
                        writeToFile(save_file_name, workers, number_workers);
                    }
                    delete[]workers;
                    workers = NULL;
                    if (departments != NULL)
                    {
                        delete[]departments;
                        departments = NULL;
                    }
                }
            }
            else
                cout << " You will create a new database from the file\n";

            cout << "Enter file name to load: ";
            cin >> load_file_name;
            loadFromFile(load_file_name, workers, number_workers, departments, number_departments);
            break;
        case CALCULATE_NUMBER_OF_WORKERS:
            system("cls");
            calculateNumberWorkers(departments, number_departments);
            break;
        case CALCULATE_TOTAL_FUNDS_DEPARTMENT:
            system("cls");
            calculateTotalFundsbyDepartment(departments, number_departments);
            break;
        case  DELETE_INFO_BY_FIRED_WORKER:
            system("cls");
            deleteInfoByFiredWorker(workers, number_workers, departments, number_departments);
            break;
        case STAFF_MOVE:
            system("cls");
            int move_worker_number;
            cout << "Enter the number of worker to move him in the another department: ";
            cin >> move_worker_number;
            staffMove(workers[move_worker_number - 1], departments, number_departments);
            break;
        case LIST_WORKER_BY_DEPARTMENT:
            system("cls");
            listWorkerByDepartment(departments, number_departments);
            break;
        case TOTAL_FUNDS:
            system("cls");
            totalFunds(departments, number_departments);
            break;
        case EXIT:
            system("cls");
            quit(exit, workers, number_workers);
            break;
        }
        return exit;
}

void DrawMenu(Worker *workers, int number_workers, Department *departments, int number_departments)
{
    menuitems sel = CREATE_DATABASE; // Number of the current menu item
    SetConsoleTextAttribute(hStdOut, inactiveItemAttributes);
    system("cls");
    for (int i = 0; i < NUMBER_MENU; i++)
    {
        gotoxy(menu[i].x, menu[i].y);
        cout << menu[i].name_menu;
    }
    itemMenu(sel, true);
    showCursor(false);
    fflush(stdin);
    int iKey;
    bool exit = false;
    while (!exit)
    {
        if (_kbhit())
        {
            iKey = _getch();
            switch (iKey)
            {
            case DOWN:
                if (sel < NUMBER_MENU - 1) {
                    itemMenu(sel, false);
                    sel = (menuitems)(sel + 1);
                    itemMenu(sel, true);
                }
                else {
                    itemMenu(sel, false);
                    sel = CREATE_DATABASE;
                    itemMenu(sel, true);
                }
                showCursor(false);
                break;
            case UP:
                if (sel >0) {
                    itemMenu(sel, false);
                    sel = (menuitems)(sel - 1);
                    itemMenu(sel, true);
                }
                else {
                    itemMenu(sel, false);
                    sel = EXIT;
                    itemMenu(sel, true);
                }
                showCursor(false);
                break;
            case ENTER:
                gotoxy(curspos.X, curspos.Y);// Moves the cursor from the menu bar at the same position
                SetConsoleTextAttribute(hStdOut, workWindowAttributes);
                exit = menuAction(sel, workers, number_workers, departments, number_departments);
                _getch();
                if (!exit) DrawMenu(workers, number_workers, departments, number_departments);
                break;
            case ESCAPE:
                system("cls");
                quit(exit, workers, number_workers);
                getCursorPosition(); //program completion
            } // switch
        } // if (kbhit)
    } // while (!exit)
}

int main()
{
    int number_workers = 0, number_departments = 0;
    Worker *staff = NULL;
    Department *departments = NULL;

    SetConsoleTitle(L"MENU");
    GetConsoleScreenBufferInfo(hStdOut, &csbInfo);
    consolRect = csbInfo.srWindow; // coordinates of the corners console
    SetConsoleTextAttribute(hStdOut, workWindowAttributes);

    system("cls"); //set attributes of color workspace

    if (SetWindow(135, 50))
         DrawMenu(staff, number_workers, departments, number_departments);

    for (int i = 0; i < number_departments; ++i)
        delete[]departments[i].workers;
    delete[]departments;

    delete[]staff;

    return 0;
}

Здавалося, й тут нічого страшного, але... Ось дійшла до такого:

Прихований текст
void WriteToFile(ofstream &out)
    {
        out.write(reinterpret_cast<char*>(&account_number_salary), sizeof(account_number_salary));
        out.write(reinterpret_cast<char*>(surname.c_str), surname.length());
        out.write(reinterpret_cast<char*>(name.c_str), name.length());
        out.write(reinterpret_cast<char*>(birthday.c_str), birthday.length());
        out.write(reinterpret_cast<char*>(city.c_str), city.length());
        out.write(reinterpret_cast<char*>(street.c_str), street.length());
        out.write(reinterpret_cast<char*>(&house_number), sizeof(house_number));
        out.write(reinterpret_cast<char*>(&flat_number), sizeof(flat_number));
        out.write(reinterpret_cast<char*>(phone_number.c_str), phone_number.length());
        out.write(reinterpret_cast<char*>(education.c_str), education.length());
        out.write(reinterpret_cast<char*>(&experience), sizeof(experience));
        out.write(reinterpret_cast<char*>(&total_projects_cost), sizeof(total_projects_cost));
        out.write(reinterpret_cast<char*>(position.GetName().c_str), position.GetName().length());
        out.write(reinterpret_cast<char*>(position.GetWorkingHours()), sizeof(position.GetWorkingHours()));
        out.write(reinterpret_cast<char*>(position.GetSalary()),sizeof(position.GetSalary()));
        out.write(reinterpret_cast<char*>(position.GetNumberWorkDuties()), sizeof(position.GetNumberWorkDuties()));

        for (int i = 0; i < position.GetNumberWorkDuties(); ++i)
            out.write(reinterpret_cast<char*>(position.GetWorkDutieByPosition(i + 1).c_str), position.GetWorkDutieByPosition(i + 1).length());

        out.write(reinterpret_cast<char*>(&current_number_projects), sizeof(current_number_projects));

        for (int i = 0; i < current_number_projects; ++i)
        {
            out.write(reinterpret_cast<char*>(projects[i].GetName().c_str), projects[i].GetName().length());
            out.write(reinterpret_cast<char*>(projects[i].GetDuration()), sizeof(projects[i].GetDuration()));
            out.write(reinterpret_cast<char*>(projects[i].GetWorkingHours()), sizeof(projects[i].GetWorkingHours()));
            out.write(reinterpret_cast<char*>(projects[i].GetProjectCost()), sizeof(projects[i].GetProjectCost()));
            out.write(reinterpret_cast<char*>(projects[i].GetNameCustomer().c_str), projects[i].GetNameCustomer().length());
        }

        out.write(reinterpret_cast<char*>(department.GetName().c_str),department.GetName().length());
        out.write(reinterpret_cast<char*>(department.GetMajorDepartmentName().c_str), department.GetMajorDepartmentName().length());
        out.write(reinterpret_cast<char*>(department.GetAmountPrize()), sizeof(department.GetAmountPrize()));
        //out.write(reinterpret_cast<char*>(department.GetNumberWorkers()), sizeof(department.GetNumberWorkers()));

        //for (int i = 0; i < department.GetNumberWorkers(); ++i)
        //    out.write(reinterpret_cast<char*>);
        out.write(reinterpret_cast<char*>(department.GetNumberPositions()), sizeof(department.GetNumberPositions()));
        for (int i = 0; i < department.GetNumberPositions(); ++i)
            out.write(reinterpret_cast<char*>(department.GetPosition(i + 1).c_str), department.GetPosition(i + 1).length());
    }

Проблеми, які виникли і не знаю з якого боку тепер підступитися:
1. Не можу серіалізувати поля типу double. Як з ними правильно поступити?
2. При записі у файл підрозділу, в кому є Worker, потрібно записати масив об'єктів Worker, які працюють у цьому підрозділі. А це виходить замкнене коло. Як????

2

Re: Як зберегти у файлі (файлах) об'єкти двох взаємозв'язаних класів?

А з рядками у вас все гаразд? c_str досі була функція, і її треба викликати. Ви ж записуєте в файл код функції. Крім того, у вас половина даних має фіксований розмір, а половина - рядки довільного розміру. Як при читанні дізнатися, що рядок вже закінчився? Треба:
- або фіксувати довжину в файлі;
- або ставити маркер (тобто записувати на 1 символ більше, з '\0');
- або записувати перед рядком його довжину;
і відповідним чином читати.
float і double записуються в бінарний файл так само, як і int - у них фіксований розмір.
Не зовсім зрозумів

pika1989 написав:

При записі у файл підрозділу, в кому є Worker, потрібно записати масив об'єктів Worker, які працюють у цьому підрозділі

У вас у різних підрозділів різні файли? То і пишіть спершу інформацію про підрозділ, а потім про кожного працівника окремо. Коли читатимете файл, додаватимете по одному в загальний список. Файл має зберігати не копію вашої структури в пам'яті, а інформацію для її відновлення.
Якщо ж у вас є в файлі кілька складно пов'язаних сутностей (наприклад, департамент зберігає посилання на працівників, але працівники можуть бути в кількох департаментах одночасно), то це вже теорія баз даних. Вам необхідно визначити для кожного працівника ключ - унікальне значення чи комбінацію значень, яке дозволяє однозначно його визначити. Можна роздати працівникам ID-коди (додати окреме поле), можна використовувати як ключ ПІБ працівника і т.д. Очевидно, що, скажімо, зарплата не є визначальною характеристикою працівника, бо, по-перше, змінюється (хоча якщо читати/зберігати за один раз всю інформацію, це не має значення), а по-друге, може бути однаковою в різних працівників, що робить неможливим однозначне визначення. Тоді в департаменті замість посилання на працівника треба буде зберігати у відповідному місці цей ключ, який при читанні в пам'ять буде замінюватися на посилання.