[C++] tablice w klasach

0

Dostałem zadanie przerobić program z rekordami, bazujący na strukturach i plikach binarnych, na model klasowy. Zacząłem przerabiać ale okazało się że nie mam pojęcia jak tworzyć dobre tablice dla klas. Czy ktoś na podanym niżej przykładzie, mógłby mi doradzić jak zadeklarować tablicę do końca i wczytać dane z pliku (sprawdzenie czy jakiekolwiek rekordy się w pliku znajdują).

Przy poniższym kodzie zakończenie programu wywołuje błąd.

#include <cstdlib>    
#include <iostream>    
#include <stdio.h>    
#include <cstring> 
 
using namespace std;    

class pracownik //klasa dla pracownika    
{    
protected:    
   string imie;   
   string nazwisko;  
   string stanowisko;  
   int ID;  
   int rok;  
public:    
   //konstruktor    
   pracownik(){} 
   //ID, imie, nazwisko, stanowisko, rok
   pracownik(int, string, string, string, int);    
};    

//dziedziczenie
class sprzedawca : public pracownik    
{    
private:    
    float sprzedane;     
public:    
   sprzedawca(){} 

   //ID, imie, nazwisko, stanowisko, rok, sprzedaz
   sprzedawca(int, string, string, string, int, float);    
   
   static sprzedawca *TablicaSprzedawca;

   //destruktor tablicy
   ~sprzedawca(){delete TablicaSprzedawca;}
   
   int sprID();
};  

sprzedawca *sprzedawca::TablicaSprzedawca = NULL;
  

//konstruktor    
pracownik::pracownik(int sellerID, string imieS, string nazwiskoS, string stanowiskoS, int rokS)    
{   
     ID = sellerID;      
     imie = imieS;     
     nazwisko = nazwiskoS;
     stanowisko = stanowiskoS;
     rok = rokS;
}    

sprzedawca::sprzedawca(int sellerID, string imieS, string nazwiskoS, string stanowiskoS,int rokS, float Sell): pracownik(sellerID, imieS, nazwiskoS, stanowiskoS, rokS)    
{    
     sprzedane = Sell;    
}  
  

                                       //metody  

int sprzedawca::sprID()
{
    return ID;
}


                                  // glowny program    

int main(int argc, char *argv[])    
{    
     //zmienne programu  
     int opcja, licznik=0;  
     bool koniec=false;  

     //zmienne plikowe    

     char bazaS[] = "sprzedawca.dat"; 
     FILE* plik;  

     //zmienna klasowa  
     string imie, nazwisko, stanowisko;  
     int rok, ID;  
     float sprzedaz;    
    
     //tablica klasy  (domyslam sie ze niepoprawna)

     //sprzedawca s[100], buf[100]; 


     do  
     {  

          //sprawdzam ilosc wpisow

          licznik=0;
          plik = fopen(bazaS, "rb");
          fread(&s,sizeof(s),1,plik);
          for(int j=0;j<100;j++)
          {
               
               if(s[j].sprID()!=NULL) 
                    licznik++;
          }
          fclose(plik);


          //menu
        
          cout<<"Prosze wybrac opcje poprzez wybranie odpowiedniej cyfry"<<endl;  
          cout<<"1. Dodaj rekord"<<endl;  
          cout<<"2. Usun rekord"<<endl;  
          cout<<"3. Usun wszystkie rekordy"<<endl;  
          cout<<"4. Wyswietl baze pracownikow"<<endl;  
          cout<<"5. Wyswietl pracownikow z premia powyzej 3000 zl"<<endl;  
          cout<<"6. Zakoncz"<<endl<<endl;  
          cout<<"Aktualna liczba rekordow: "<<licznik<<endl;  
          cin>>opcja; 
          cin.ignore();      
          if((opcja>6)||(opcja<1))  
          {  
               cout<<endl<<"Uwaga!!! Zakres od 1-6."<<endl<<endl;  
               system("PAUSE");  
               system("cls");  
          }  
          else  
          {  
               if(opcja == 1) 
               { 
      
     
               } 
               else if(opcja == 2) 
               { 
      
               
               } 
               else if(opcja == 3) 
               { 
      
               } 
               else if(opcja == 4) 
               { 
    

               } 
               else if(opcja == 5) 
               { 
       
               } 
               else if(opcja == 6) 
               { 
                    koniec=true; 
               } 
     
               system("PAUSE");  
               system("cls");  
          }  

     }while(koniec==false);  
    
     return EXIT_SUCCESS;    
} 
0

Zamiast robic drabinke IF-ELSE po int'ach, zapoznaj sie ze switch()

Twoj problem nie polega na tym, ze "tablica jest zła", tylko na tym, że odczytywanie pliku ktorego probowales dokonac jest ZUE.

Wiesz czym sa wskazniki? Wiesz dlaczego zapisywanie >wskaznika< do pliku i probowanie go potem odczytac jest zwykle bezsensu?
Zakladam, ze tak. Jesli nie - nie czytaj dalej, tylko upomnij sie o wytlumaczenie czemu nie mozna/bezsensu i potem przeczytaj ponizsze.


Ok, wiesz ze zapis żywych wskaznikow jest kiepskim pomyslem. W takim razie, musisz zwrocac dokaldnie uwage, na to co masz w swoich klasach! Twoj SPRZEDAWCA ma w sobie pola typu string. Czym jest string? jak jest zbudowany? std::string to nie jest po prostu wcisnieta w klase char[1024], on przeciez moze zmieniac rozmiar. Jest to dosc zlozony twor, m.in. pamietajacy w sobie wskaznik na dynamicznie alokowana tablice znakow. O. <-patrz. String zawiera wskaznik. To oznacza, ze proba ŻYWEGO zapisu lub ŻYWEGO odczytu stringa jako serii bajtow sie nie uda!! I tak samo Twojej klasy, ktora tegos stringa zawiera, gdyz czytanie hurtem obiektu takiej klasy leci takze przez stringi... Nie mozesz tez odczytac bezposredni -->do--> stringa/Twojej klasy poprzez FREAD. Wskazniki, referencje, blokuja sliczne hurtowe fread/fwrite po wszystkim. Hurtem fread/fwrite mozesz traktowac tylko te typy danych, ktore nazywa sie POD, PlainOldData. Twoja klasa zawiera stringi ktore nie sa POD, wiec cala Twoja klasa nie jest POD.
A co to jest dokladnie ten POD/PlainOldData? odsyłam do: Parashift's C++ FAQ 26.7

Zeby uzyc tutaj fread/fwrite poprawnie, musisz niestety:

  • fread: odczytac swoj obiekt kawalkami, pole-po-polu, nie hurtem calosc. proste rzeczy jak inty, double, .. - mozesz czytac bezposrednio od razu do pola klasy. stringa jednak musisz na okolo. musisz zrobic sobie swoj bufor tekstowy, fread'nąć do niego, a nastepnie wykonac Twojobiekt.polestring.Assign(ptr-na-bufor, ptr-na-ostatni-znak-odczytany-w-buforze+1). Alternatywnie, mozesz czytac po jednym bajcie i doklejac pojedynczo do stringa..
  • fwrite: tutaj prosciej. Co prawda rowniez nie masz prawa wziac sobie &string i czytac żywcem, ale za to, mozesz stringa poprosic o jego zawartosc hurtem - string.c_str() zwraca Ci char const* ktore mozesz od razu podac fwriteowi do zapisania do pliku

i nie waz sie probowac robic fread do tego co string.c_str zwraca! c_str zwraca dane tymczasowe, dlatego sa const. nawet jesli sprobujesz i wcisniesz do tego co c_str zwraca swoje dane, te dane wyparuja.

0

Nie za bardzo wiem jak wczytując z pliku lub zapisując odnosić się tylko i wyłącznie do pojedynczych wartości (np do imienia) z klasy.

W klasie mam imie, nazwisko i stanowisko. Jak mam wczytać do stringa a później je rozróżnić na te poszczególne elementy?

0

nie tak. masz zapisywac/odczytywac osobno elementy skladowe, a potem upychac je do obiektu docelowego.

np. majacstruct BLE {int bum, bam, bim; }

czytanie hurtem-do-calego obiektu

BLE x;
fread(&x, sizeof(BLE), 1, plik);

czytanie kolejno pojedynczych wartosci:

BLE x;
fread(&x.bum, sizeof(int), 1, plik);
fread(&x.bam, sizeof(int), 1, plik);
fread(&x.bim, sizeof(int), 1, plik);

dla tej struktury BLE, obydwie w/w metody sa rownowazne, jesli pominac sprawy ewentualnego alignu..

w przypadku gdy w Twoim obiekcie jest cokolwiek co NIE jest POD'em, np. std::string, tracisz prawo/mozliwosc czytania hurtem i musisz zaczac czytac pojedynczo -- gdyz NIE masz prawa/mozliwosci czytania bezposrednio do string/niePOD

struct BUM{ int  bam, bim; string ble };

BUM x;

// fread(&x, sizeof(BUM), 1, plik);   // NIEWOLNO, gdyz x.ble ZOSTANIE USZKODZONE w trakcie. trzeba pojedynczo

fread(&x.bam, sizeof(int), 1, plik); //raz...
fread(&x.bim, sizeof(int), 1, plik); //dwa... iiii..

//fread(&x.ble, sizeof(string), 1, plik); // NIEWOLNO, gdyz string ZOSTANIE USZKODZONY poprzez to

//fread(&x.ble.c_str(), x.ble.size(), 1, plik); // NIEWOLNO, gdyz nawet jak sie uda, to dane wyparuja

char bufor[ilestam]; // moze byc tez vector<char>, lub cokolwiek tablicowatego
fread(&bufor, ...ilestam..., 1, plik);
x.ble.assign(bufor, bufor+ilestam);   // lub dowolny innu sposob na skopiowanie danych do string'a

oczywiscie musisz wiedziec, ile znakow czytasz, zwlaszcza jesli dlugosc jest dowolna.
nalepiej zatroszczyc sie o to podczas zapisu stringa do pliku: np. najpierw zapisac jego dlugosc, a dopiero potem zawartosc

1 użytkowników online, w tym zalogowanych: 0, gości: 1