Здравствуйте!
Есть интересный код из учебника, в котором приводится пример программы, которая записывает в файл и извлекает из него объекты разной величины.
В целом механика понятна и к ней вопросов нет.
Вопрос только один: ГДЕ происходи инициализация статической переменной n нулём???
Я поставил от себя два cout в строках 29 и 95. Так вот, первое использование переменной, которая на мой взгляд на тот момент ещё нигде не инициализирована, происходит в методе add(); после выбора персонажа, и там она уже где-то обзавелась значением ноль!
Прошу более внимательных и знающих показать, где же происходит инициализация?
Я искал долго с использованием точек останова, так вот, словно в насмешку, значение n компилятор просто не показывает. Я проставил точки останова ВООБЩЕ везде, где есть n))) Я проставил проверочные cout во многих местах с точками останова, он просто не показывает переменную n внизу VS-2019 и всё!)))
Вот код:
// Файловый ввод/вывод объектов employee
// Поддержка объектов неодинаковых размеров
#include <fstream>      // для потоковых файловых функций
#include <iostream>
#include <typeinfo>     // для typeid()
using namespace std;
#include <process.h>    // для exit()
const int LEN = 32;     // Максимальная длина фамилий
const int MAXEM = 100;  // максимальное число работников
enum employee_type { tmanager, tscientist, tlaborer };
///////////////////////////////////////////////////////////
class employee                // класс employee 
{
private:
    char name[LEN];           // фамилия работника
    unsigned long number;     // номер работника
    static int n;             // текущее число работников
    static employee* arrap[]; //массив указателей на
                              // класс работников
public:
    virtual void getdata()
    {
        cout << "N равно: " << n << "\n";//тут при первом вводе первой персоны n равно 1 (но сначала 95)
        cin.ignore(10, '\n');
        cout << "  Введите фамилию: "; cin >> name;
        cout << "  Введите номер: ";    cin >> number;
    }
    virtual void putdata()
    {
        cout << "\n  Фамилия: " << name;
        cout << "\n  Номер: " << number;
    }
    virtual employee_type get_type(); // получить тип
    static void add();                // добавить работника
    static void display();            // вывести данные обо всех
    static void read();               // чтение из файла
    static void write();              // запись в файл
};
//---------------------------------------------------------
//статические переменные
int employee::n;                  // текущее число работников
employee* employee::arrap[MAXEM]; // массив указателей на
                                  // класс работников
///////////////////////////////////////////////////////////
//класс manager (менеджеры)
class manager : public employee
{
private:
    char title[LEN];  // титул ("вице-президент" и т. п.)
    double dues;      // Налоги гольф-клуба
public:
    void getdata()
    {
        employee::getdata();
        cout << "  Введите титул: ";       cin >> title;
        cout << "  Введите налоги: "; cin >> dues;
    }
    void putdata()
    {
        employee::putdata();
        cout << "\n  Титул: " << title;
        cout << "\n  Налоги гольф-клуба: " << dues;
    }
};
///////////////////////////////////////////////////////////
//класс scientist (ученые)
class scientist : public employee
{
private:
    int pubs;              // число публикаций
public:
    void getdata()
    {
        employee::getdata();
        cout << "  Введите число публикаций: "; cin >> pubs;
    }
    void putdata()
    {
        employee::putdata();
        cout << "\n  Число публикаций: " << pubs;
    }
};
///////////////////////////////////////////////////////////
//класс laborer (рабочие)
class laborer : public employee
{
};
///////////////////////////////////////////////////////////
//добавить работника в список (хранится в ОП)
void employee::add()
{
    cout <<"N равно: "<< n << "\n";             //вот здесь n  уже равно ноль
    char ch;
    cout << "'m' для добавления менеджера"
        "\n's' для добавления ученого"
        "\n'l' для добавления рабочего"
        "\nВаш выбор: ";
    cin >> ch;
    switch (ch)
    {          //создать объект указанного типа
    case 'm': arrap[n] = new manager;  break;
    case 's': arrap[n] = new scientist; break;
    case 'l': arrap[n] = new laborer;  break;
    default: cout << "\nНеизвестный тип работника\n"; return;
    }
    arrap[n++]->getdata();  //Получить данные от пользователя
}
//---------------------------------------------------------
//Вывести данные обо всех работниках
void employee::display()
{
    for (int j = 0; j < n; j++)
    {
        cout << (j + 1);                // вывести номер
        switch (arrap[j]->get_type()) //вывести тип 
        {
        case tmanager:  cout << ". Тип: Менеджер";  break;
        case tscientist: cout << ". Тип: Ученый"; break;
        case tlaborer:   cout << ". Тип: Рабочий";  break;
        default: cout << ". Неизвестный тип";
        }
        arrap[j]->putdata();           // Вывод данных
        cout << endl;
    }
}
//---------------------------------------------------------
//Возврат типа объекта
employee_type employee::get_type()
{
    if (typeid(*this) == typeid(manager))
        return tmanager;
    else if (typeid(*this) == typeid(scientist))
        return tscientist;
    else if (typeid(*this) == typeid(laborer))
        return tlaborer;
    else
    {
        cerr << "\nНеправильный тип работника"; exit(1);
    }
    return tmanager;
}
//---------------------------------------------------------
//Записать все объекты, хранящиеся в памяти, в файл
void employee::write()
{
    int size;
    cout << "Идет запись " << n << " работников.\n";
    ofstream ouf;           // открыть ofstream в двоичном виде
    employee_type etype;   // тип каждого объекта employee
    ouf.open("EMPLOY.DAT", ios::trunc | ios::binary);//trunc-обрезать файл до нуля если он уже есть
    if (!ouf)
    {
        cout << "\nНевозможно открыть файл\n"; return;
    }
    for (int j = 0; j < n; j++)  // Для каждого объекта
    {                     // получить его тип
        etype = arrap[j]->get_type();
        // записать данные в файл
        ouf.write((char*)&etype, sizeof(etype));
        switch (etype)         // find its size
        {
        case tmanager:  size = sizeof(manager); break;
        case tscientist: size = sizeof(scientist); break;
        case tlaborer:  size = sizeof(laborer); break;
        }      
        ouf.write( (char*)(arrap[j]), size );  //запись объекта employee в файл
        if (!ouf)
        {
            cout << "\nЗапись в файл невозможна\n"; return;
        }
    }
}
//---------------------------------------------------------
//чтение всех данных из файла в память
void employee::read()
{
    int size;               // размер объекта employee 
    employee_type etype;    // тип работника
    ifstream inf;           // открыть ifstream в двоичном виде
    inf.open("EMPLOY.DAT", ios::binary);
    if (!inf)
    {
        cout << "\nНевозможно открыть файл\n"; return;
    }
    n = 0;                  // В памяти работников нет
    while (true)
    {                     // чтение типа следующего работника
        inf.read((char*)&etype, sizeof(etype));
        if (inf.eof())       // выход из цикла по EOF
            break;
        if (!inf)              // ошибка чтения типа
        {
            cout << "\nНевозможно чтение типа\n"; return;
        }
        switch (etype)
        {                   // создать нового работника
        case tmanager:      // корректного типа
            arrap[n] = new manager;
            size = sizeof(manager);
            break;
        case tscientist:
            arrap[n] = new scientist;
            size = sizeof(scientist);
            break;
        case tlaborer:
            arrap[n] = new laborer;
            size = sizeof(laborer);
            break;
        default: cout << "\nНеизвестный тип в файле\n"; return;
        }                   // чтение данных из файла
        inf.read((char*)arrap[n], size);
        if (!inf)              // ошибка, но не EOF
        {
            cout << "\nЧтение данных из файла невозможно\n"; return;
        }
        n++;                  // счетчик работников увеличить
    }  //end while
    cout << "Идет чтение " << n << " работников\n";
}
///////////////////////////////////////////////////////////
int main()
{
    system("chcp 1251>nil");
    char ch;
    while (true)
    {
        cout << "'a' – добавление сведений о работнике"
            "\n'd' - вывести сведения обо всех работниках"
            "\n'w' – записать все данные в файл"
            "\n'r' – прочитать все данные из файла"
            "\n'x' - выход"
            "\nВаш выбор: ";
        cin >> ch;
        switch (ch)
        {
        case 'a':           // добавить работника
            employee::add(); break;
        case 'd':           // вывести все сведения
            employee::display(); break;
        case 'w':           // запись в файл
            employee::write(); break;
        case 'r':           // чтение всех данных из файла
            employee::read(); break;
        case 'x': exit(0);  // выход
        default: cout << "\nНеизвестная команда";
        }  //end switch
    }  //end while
    return 0;
}  //end main()
Напечатайте или вставьте сюда код