Zapis i odczyt struktur z plików binarnych to pestka a co z klasami gt;

T72

Umiesz już zapisać do pliku binarnego strukture i ją wczytać? A co z klasą która ma również metody? Jest łatwy sposób otóż mamy sobie klase:

class osoba 
{ 
private: 
   int liczba; 
   char imie[50]; 
   double srednia; 

public: 
   osoba(void){}; 
   osoba(int l, char * i, double s) : liczba(l), srednia(s) 
   { 
      strcpy(imie, i); 
   } 
   void zapisz(void); 
   void odczytaj(void); 
   void pokaz(void); 
}; 

I chcemy żeby funkcja zapisz i odczytaj pracowały na plikach binarnych. Tak więc robimy tak:

void osoba::zapisz(void) 
{ 
   fstream plik; 

   plik.open("osoba.bin", ios::out | ios::binary); 
   plik.write((char*)this,sizeof(int)+sizeof(double) + sizeof(char)*50+2 ); 
   plik.close(); 
}

Czyli zapis klasy różni się od zapisu struktury tylko miejscem gdzie podajemy rozmiar. Trzeba tam podać sumy rozmiarów wszystkich zmiennych które sa w klasie + jeszcze 2 czyli: sizeof(int) bo int liczba sizeof(double) bo double srednia sizeof(char)*50 bo char imie[50] no i na końcu + 2 :) odczyt analogicznie:

void osoba::odczytaj(void) 
{ 
   fstream plik; 

   plik.open("osoba.bin", ios::in | ios::binary); 
        plik.read((char*)this,sizeof(int)+sizeof(double) + sizeof(char)*50+2); 
        plik.close(); 
}

12 komentarzy

Oj, nie wystarczy zwykłe sizeof(obiekt). Nie wystarczało już w C, gdzie pracuje się tylko na zwykłych pakietach zmiennych, zwanych też strukturami. Nie wystarcza więc to i w C++, gdzie oprócz zmiennych, mamy w klasie funkcje, oraz vtable, czyli tablicę funkcji wirtualnych (i jeszcze jest wskaźnik na type info, potrzebne do typeid() i dynamic_cast, ale to można wyłączyć w kompilatorze). Oprócz tego, każda zmienna składowa może być klasą, z własnymi zmiennymi, funkcjami, etc. Ogółem, ta metoda zapisu może się przydać, jeżeli ktoś ma zamiar pisać gry na PlayStation, czy inne konsole - na większości można zagwarantować, że po ponownym uruchomeniu gry/programu układ pamięci będzie taki sam. Niestety, na komputerach PC jest to bardzo mało prawdopodobne, i już z tego powodu nie wolno zapisywać wskaźników, bo po ich wczytaniu wynik działania programu jest niezdefiniowany [czyli może działać dobrze, a nawet lepiej ^^, albo sformatować dysk, wysyłając wcześniej dużo sprośnych e-maili do wszystkich przyjaciół w książce adresowej]. Do tego wszystkiego dochodzą jeszcze problemy z wyrównywaniem w pamięci, o których wspomniał MarcinEc. Jednak nie do końca zgadzam się z punktem 1 jego komentarza. Struktury i klasy nie różnią się niczym, ale w C++. Między strukturą w C, a klasą/strukturą w C++ różnic jest już bardzo dużo (część wspomniałem wyżej). Pozdrawiam.

a do czego to wogole sluzy ? :)

  1. Co to jest kalasa? Literówka, odkrywcze no nie? Jak się nie ma nic do powiedzenia to się nic nie mówi.
  2. Dynamiczne tablice? Ja tu nie mówie jak zapisywać wszystkie obiekty, kontenery itp. to już inna bajka. Ja mówi o zapisie klasy a jak w niej jest coś co zapisuje się jakoś inaczej to trzeba o to odzielnie zadbać. Nie będe opisywał wszystkiego bo nie sposób.
  3. zwykłe sizeof(obiekt) jakoś nie działa :) ten artykuł pisałem pod natchnieniem bo jeden typ na forum (innym) miał właśnie taki problem bo zwykłe sizeof nie działało. A mój pomysł poskutkował.
  4. co do ułożenia danych w pamięci, hmmm sam nie wiem. Wiem tylko że już wiele razy kożystałem z tej metody i jak dotąd zawsze działało...

Temporal: nie, chwila. Zapisujemy DANE (pola) klasy, struktury, a nie logikę ich działania :]
sizeof(obiekt) wystarczy jeśli robimy zrzut pamięci obiektu (jakkolwiek ja wiem, że to wielka lipa).
Żadne vtable, żadne type info, żadne this, żadne metody nie muszą zostać zapisane, a niektóre to po prostu niemożliwość żeby zapisać!
Niektóre skomplikowane przypadki (struktury ze wskaźnikami, drzewami, cyklami, połączeniami (w sensie związków)) są tu: http://www.parashift.com/c++-faq-lite/serialization.html
Radzę przeczytać!

wystarczy sizeof(nazwa_obiektu), policzy to dokładny rozmiar danych w obiekcie i to niezależnie od ustawień kompilatora... w końcu po to To jest!

Hmmm...

  1. Czy między klasą a strukturą w C++ jest aż tak wielka różnica? Nie. Inna jest tylko domyślna widoczność składowych.
  2. Program oczywiście zawiera poważny błąd dotyczący założeń co do przydziału pamięci dla zmiennych składowych. Zmienne nie muszą być umieszczone jedna za drugą, ponieważ dochodzi jeszcze wyrównanie do np. 4 bajtów. Akurat tu fuksem mamy int i double i zapewne domyślne wyrównanie do 4 bajtów na kompilatorze autora...
  3. Wynikające z 2: dlaczego nie po prostu sizeof(osoba)?
  4. Ogólnie taki sposób zapisu struktur nie jest prawidłowy! Należy zapisywać zmienne/dane pojedynczo, a nie wszystko-na-raz. Dlaczego? Różny rozmiar typów dla różnych kompilatorów, inne wyrównywanie, dane o zmiennym rozmiarze, itp. Same problemy.
  5. No i po co +2 :) ?

No to wtedy metoda jest zmienną i jej wartość można również zapisać (adres do procedury) . Chyba się nie myle ??

A co jak tabice będą dynamiczne, bo tym sposobem to odczytuje tylko śmieci???

A co z kalsą która ma również metody?

A co to jest kalsa?

wiesz, może kup sobię jakąś książkę??

ale mógłbyś wyjaśnić również po co to +2... (się domyślam, ale artykuł jest przez to niekompletny).

Nie łatwiej wewnątrz klasy stworzyć strukturę ? Przecież zależnie od kompilatora, w klasie dane nie muszą byc w zaden sposob ułozone liniowo jedna za drugą.