Baza danych zbudowana na klasach

0
#include <iostream>
#include <fstream>
#include <string>
#include <cstring>
#include <cstdlib>

using namespace std;


class produkt
{
      //friend class warzywo; // deklaracja przyjaŸni, aby mo¿liwy by³ dostêp do pó³ privat w nowej klasie pochodnej
      protected:              // zaprzyjaŸnienie zamienione na rozwi¹zanie z polami protected
         int lp;
         string name;  // nazwa produktu
         double count;   // liczba produktów
         string unit;   // jednostka miary
         double prize;   // cena netto 1 sztuki
         double vat;     // wartoϾ podatku VAT
      public:
 	     produkt();                   // konstruktor
 	     produkt(int Nlp, string Nname, double Ncount, string Nunit, double Nprize, double Nvat);                   // konstruktor
         void wypelnij(void);
         void pokaz(void);
         //virtual void wypelnij(void);
         //virtual void pokaz(void);
         produkt(produkt &l);     // konstruktor kopiujacy
         ~produkt();                  // destruktor
         int pole_lp(void);
         void pole_lp(int);
};

produkt::produkt(int Nlp, string Nname, double Ncount, string Nunit, double Nprize, double Nvat)
{
        lp=Nlp;
        name=Nname;
        count=Ncount;
        unit=Nunit;
        prize=Nprize;
        vat=Nvat;
}
produkt::produkt()
{
        lp = 0;
}

produkt::produkt(produkt &l)
{
        lp=l.lp;
        name=l.name;
        count=l.count;
        unit=l.unit;
        prize=l.prize;
        vat=l.vat;
}

produkt::~produkt()
{
 ;
}

void produkt::wypelnij(void)
{
 cout << "Podaj nazwe:\n";
 cin >> name;
 cout << "Podaj ilosc:\n";
 cin >> count;
 cout << "Podaj jednostke miary:\n";
 cin >> unit;
 cout << "Podaj cene:\n";
 cin >> prize;                        // UWAGA obowi¹zuje notacja z kropk¹ .
 cout << "Podaj stawke VAT:\n";
 cin >> vat;

}
void produkt::pokaz(void)
{
        cout << endl;
        cout << lp << "\t";
        cout << name << "\t";
        cout << count << "\t";
        cout << unit << "\t";
        cout << prize << "\t";
        cout << vat << endl;
}
int produkt::pole_lp(void)
{
 return(lp);
}
void produkt::pole_lp(int x)
{
 lp = x;
}

class wezel {
public:
    wezel *nastepny;
    produkt *zawartosc;
    int indeks;
};

class baza {
    wezel *pierwszy, *ostatni;
    int licznik;
public:
    baza();
    ~baza();
    void dodaj(produkt *prod);
    void wyswietl();
    void usun(int idx);
    void zapisz();
    void wczytaj();
};


baza::baza() {

    pierwszy = ostatni = NULL;
    licznik = 0;

};

baza::~baza() {

    wezel *p;

    while(pierwszy)
    {
        p = pierwszy -> nastepny;
        delete pierwszy;
        pierwszy = p;
    }

}

void baza::dodaj(produkt *prod) {

wezel *p = new wezel;

   if(ostatni)
    {
       ostatni->nastepny = p;
       p->zawartosc = prod;
    }
       p->nastepny = NULL;
       ostatni = p;
    if(!pierwszy)
    {
        pierwszy = ostatni;
    }
    licznik++;
};

void baza::usun(int idx) {

};

void baza::wyswietl() {

wezel *p = new wezel;

      if(!pierwszy) cout << "Lista jest pusta." << endl;
      else
      {
        p = pierwszy;
        while(p)
        {
        p->zawartosc->pokaz();
        p = p->nastepny;
        }
        cout << endl;
      }
};

int main(void)
{
        baza db1;
        produkt *p1 = new produkt(5, "maslo", 10, "sztuk", 1.00, 0.07);
        db1.dodaj(p1);
        db1.wyswietl();
        return 0;
}

Mam za zadanie napisać bazę danych na klasach(jak widać wyżej). Na samym początku walczę z problemem naruszenia pamięci. Chcę dodać nowy produkt i wyświetlić bazę wszystkich dodanych produktów. Jak na razie ni w ząb mi to wychodzi. Pewnie coś namieszałem ze wskaźnikami znając życie.

Później mam dodać jeszcze klasy pochodne do produktu, ale najpierw muszę pozbyć się pierwszego problemu. Gdzie robię błąd?

1

Błąd masz tutaj:

   if(ostatni)
    {
       ostatni->nastepny = p;
       p->zawartosc = prod;
    }

Za pierwszym razem jak wywołujesz metodę dodaj to wskaźnik ostatni ma wartość null więc
p->zawartosc = prod;
się nie wykona i wskaźnik zawartość w węźle będzie miał wartość null i podczas wywołania:
p->zawartosc->pokaz();
program się wysypie bo będziesz się próbował odwołać to wskaźnika która pokazuje na nic.
Rozwiązanie:
linijkę: p->zawartosc = prod;
umieścić od razu po tej linijce: wezel *p = new wezel;

0

Działa idealnie! Dziękuję.

Teraz napotkałem problem z usuwaniem rekordu. (Ciągle naruszam pamięć, topornie mi to wchodzi do głowy), chcę usunąć rekord podając numer "lp".

dodałem coś takiego:

void baza::usun(int idx) {
    wezel *tmp = new wezel;

    tmp = pierwszy;

    if(tmp->zawartosc->pole_lp() == idx) delete ostatni;
    else
    {
        while(tmp->zawartosc->pole_lp() != idx)
        {
            tmp=tmp->nastepny;
        }
    }
        delete tmp;
        licznik--;
};

a w main:

int x;
cout << "Numer elementu: ";
cin >> x;
db1.usun(x);
0
kaczkazdw napisał(a):
void baza::usun(int idx) {
    wezel *tmp = new wezel;

    tmp = pierwszy;

    if(tmp->zawartosc->pole_lp() == idx) delete ostatni;
    else
    {
        while(tmp->zawartosc->pole_lp() != idx)
        {
            tmp=tmp->nastepny;
        }
    }
        delete tmp;
        licznik--;
};

ja bym zrobił to tak:

void baza::usun(int idx) {
wezel *tmp = pierwszy;

 while(tmp->zawartosc->pole_lp() != idx && tmp != NULL)
    {
        tmp=tmp->nastepny;
    }

   if(tmp != NULL)
   {
        if(tmp == pierwszy) 
        {
                 pierwszy = pierwszy->nastepny;
                 delete tmp;
                   licznik--;
        }
        else
        {
                   wezel *tmp2 = pierwszy;
                   while(tmp2->nastepny != tmp)
                                      tmp2 = tmp->nastepny;
                   tmp2->nastepny = tmp->nastepny;
                   if(tmp == ostatni) ostatni = tmp2;
                   delete tmp;
                   licznik--;
         }

   

};

mogą być błędy ale myślę, że koncepcja dobra

1
tamarind17 napisał(a):

mogą być błędy ale myślę, że koncepcja dobra
To co podałeś nie może być dobre, patrz niżej:

bool baza::usun(int idx)
  {
   for(wezel *i=pierwszy,*p=0;i;p=i,i=p->nastepny)
     {
      if(i->zawartosc->pole_lp()==idx)
        {
         (p?p->nastepny:pierwszy)=i->nastepny;
         if(!pierwszy) ostatni=0;
         else if(!i->nastepny) ostatni=p;
         delete i->zawartosc;
         delete i;
         return true;
        }
     }
   return false;
  }
0

tamarind17: brakło tylko jednej klamry na końcu ale w ogólnym przypadku działało.
_13th_Dragon: był nieznaczny problem przy kompilacji na początku (brakowało zdefiniowanego "p" i kompilator się sapał o wezel *i=pierwszy) ale to już poprawiłem. Wyskakuje tylko Warning przy kompilacji, że brak jest virtualnego destruktora w klasie produktu. Ale działa jak należy

Głowię się nad kwestią zapisywania obiektów klasy do pliku i późniejsze odczytywanie ich.

Mam na razie coś takiego:

case 4:
                {
    ofstream ofs("baza.bin");
    const pamiec p(1, "Kingston", 2, "sztuk", 5, 0.07, 1024, "Intel");
    {
        boost::archive::text_oarchive oa(ofs);
        oa << p;
    }
                break;
                }
            case 5:
                {
        pamiec newp;
            {
        ifstream ifs("baza.bin");
        boost::archive::text_iarchive ia(ifs);
        ia >> newp;
        newp.pokaz();
            }
                break;
                }

to jest w switch'u w funkcji main. Jest to serializacja i deserializacja boostem i działa dla pojedynczych obiektów bazowych i obiektow pochodnych klasy bazowej.
Jak umieścić serializacje i deserializacje w metodach zapisz() wczytaj() by po wypełnieniu bazy danych zapisala wszystkie obiekty do pliku, a przy otworzeniu i wczytaniu odtworzyla stan bazy ze wszystkimi obiektami?

0

Podołałem w końcu z zapisem i odczytem. Ale do ukończenia całego projektu dzieli mnie tylko jeden problem. Mianowicie, zawsze po wczytaniu bazy danych, bo probie zakończenia Bazy Danych, cały program się wiesza na napisie "Zamykanie Programu" i nic nie rusza dalej. Nie mogę znaleźć problemu...

Oto kod:

Podaje w linkach, bo jest długawy.

Main.cpp

http://pastebin.com/n9M3CSej

functions.h

http://pastebin.com/q3ZYvzK

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