ilyachalov (ilyachalov) wrote,
ilyachalov
ilyachalov

Categories:

C++: запись объекта в файл и виртуальные функции

Речь идет про запись в режиме ios::binary. Я уже писал про запись в файл объекта простого класса с двумя полями: «Широкие символы в Windows».

Теперь случай посложнее (в учебнике Лафоре рассматривается со стр.572). Имеется базовый класс, содержащий два обычных поля, два статических поля, три виртуальных и четыре статических метода:
private:
    wchar_t name[32];         // фамилия работника
    unsigned long number;     // номер работника
    static int n;
    static employee* arrap[];
public:
    virtual void getdata();
    virtual void putdata() const;
    virtual employee_type get_type();
    static void add();
    static void display();
    static void read();
    static void write();

Также есть три производных от базового класса, каждый из которых добавляет к базовому свои поля и переопределяет виртуальные функции. Для примера я возьму только один из них, который добавляет к базовому классу одно обычное поле и переопределяет две виртуальные функции:
private:
    int pubs;                 // количество публикаций
public:
    void getdata();
    void putdata() const;

Итак, запишем объект такого производного класса в файл в режиме ios::binary. В вышеупомянутой программе из учебника Лафоре перед объектом еще записывается число типа int, несущее информацию о типе (классе) объекта. В программе используются объекты трех производных от указанного базового классов, каждый из которых обозначен, соответственно, числом 0, 1 и 2. Наш производный класс обозначен числом 1.

Я работаю в операционной системе Windows и использую компилятор среды «Visual Studio Community 2017». Результат — файл размером в 80 байт:


Первые четыре байта — это упомянутое выше значение типа int, содержащее информацию о типе (классе) объекта, оно хранит число 1:
01 00 00 00
Начиная с девятого байта записан символьный массив-буфер размером 32 символа (64 байта). Этот массив-буфер содержит нуль-терминированную строку с фамилией «Чалов» (12 байт):
27 04 30 04 3B 04 3E 04 32 04 00 00
Далее записано значение типа unsigned long, занявшее 4 байта и содержащее число 345 (номер работника):
59 01 00 00
И, наконец, последним записано значение типа int, занявшее 4 байта и содержащее число 21 (количество публикаций):
15 00 00 00
Статические поля, как можно заметить, не сохраняются.

В случае объекта простого класса размер файла был бы
4 + 64 + 4 + 4 = 76 байт.

Что же записалось в 4 байта перед полями нашего объекта производного класса?
1C 5B E7 00
Это указатель на таблицу виртуальных методов, которая автоматически создается компилятором, если программист использует виртуальные методы. (Размер указателя — 4 байта, так как моя программа является 32-разрядным приложением).

То есть компилятор в данном случае незаметно для программиста создал для объекта нашего производного класса дополнительное поле-указатель, а при записи объекта в файл в режиме ios::binary это дополнительное поле сохранилось в файл.

Эта особенность работы компилятора в описанном случае часто служит источником ошибок в программах, авторы которых не знают или забыли об этой особенности.
Tags: Образование, Программирование
Subscribe

  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic

    Your IP address will be recorded 

  • 0 comments