Здравствуйте!
Есть интересный код из учебника, в котором приводится пример программы, которая записывает в файл и извлекает из него объекты разной величины.
В целом механика понятна и к ней вопросов нет.
Вопрос только один: ГДЕ происходи инициализация статической переменной 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()
Напечатайте или вставьте сюда код