Navigacija
Lista poslednjih: 16, 32, 64, 128 poruka.

genericka klasa Kolekcija - komentari!

[es] :: C/C++ programiranje :: C/C++ za početnike :: genericka klasa Kolekcija - komentari!

[ Pregleda: 1252 | Odgovora: 1 ] > FB > Twit

Postavi temu Odgovori

Autor

Pretraga teme: Traži
Markiranje Štampanje RSS

fanfare
nezaposlen
Prnjavor,BiH

Član broj: 231940
Poruke: 27
*.teol.net.



Profil

icon genericka klasa Kolekcija - komentari!15.02.2010. u 20:59 - pre 172 meseci
Ako moze da neko prokomentarise kod koji sam napisao na sledeci zadatak:

Definisati klasu Kolekcija, koja omogućava manipulaciju skupom objekata nekoga tipa. Kolekcija se stvara prazna zadatog početnog kapaciteta (podrazumijevano 10) i koraka povećanja ( podrazumijevano 5), poslije čega se elementi dodaju jedan po jedan na kraj niza (niz+=podatak). U slučaju prepunjavanja, kapacitet se povećava za zadati korak.

Treba omogućiti da se:
• spolja može dobiti broj elemenata u kolekciji;
• spolja može dobiti podatak sa zadanim rednim brojem (niz[ind]);
• iz kolekcije izvadi podatak zadatog rednog broja, pri čemu ostali elementi popunjavaju upražnjeno mjesto;
• kolekcija isprazni;

Nekorektan redni broj pri čitanju i vađenju podataka je greška. Greške treba prijavljivati objektima izuzecima, koji imaju mogućnost ispisivanja poruke o vrsti greške.


A moj kod:
Code:
# include <iostream>

using namespace std;

class Izuzetak                           // da bi se kreirali objekti izuzeci
{
  public:
    Izuzetak(char *s) : p(s) {}
    const char *opis() const
      { return p; }
  private:
    const char *p;
};


template <class Tip,int N=10,int korak=5>
class Kolekcija
{
      public:
             Kolekcija() { n=-1; podatak=new Tip[N]; }   
             Kolekcija( Kolekcija &k) { podatak=new Tip(*k.podatak); } 
             Kolekcija &operator=(const Kolekcija &k) {  podatak=k.podatak; return *this; )
             Kolekcija &operator+=(const Kolekcija &k)
              {
                   if (n>=N-1) N+=korak;        // ako je kapacitet prepunjen
                   podatak+=k.podatak;
                   return *this; 
              }
             int broj_elemenata { return n; }
             Tip operator[](int indeks)
              {
                  return this->podatak[indeks]; 
              }
             void izvadiPodatak (Tip &);
             void isprazni() { delete [] podatak; podatak=0; n=0; }
             ~Kolekcija() { isprazni(); }
      protected:
                Tip *podatak; 
                int n;           // broj elemenata u kolekciji
};

template <class Tip,int N=10,int korak=5>
void Kolekcija<Tip,N,korak> :: izvadiPodatak ( Tip &p)
{
     for (int i=0; i<n; i++)
       if (podatak[i]==p) 
         {  for ( int j=i, k=j+1; k<n ; j++,k++)
               podatak[j]=podatak[k];
         }
};

main()
{
     Kolekcija <int,5,2> k;
     k.podatak={1,2,3,4,5};
          
     try
     {
          int indeks;
          cout<<"koji podatak zelite procitati u nizu?";
          cin>>indeks;
          if (indeks>=N-1) throw Izuzetak ("Nekorektan broj pri citanju!\n");
     }
     catch ( Izuzetak t )
        { cout << "Greska: " << t.opis(); }
     
     system("pause");
}
         
          
      
      



              
 
Odgovor na temu

Mihajlo Cvetanović
Beograd

Moderator
Član broj: 37636
Poruke: 1249



+96 Profil

icon Re: genericka klasa Kolekcija - komentari!16.02.2010. u 10:08 - pre 172 meseci
Code:
class Izuzetak
{
    Izuzetak(char *s) : p(s) {}
    const char *p;
};

String mora ceo da se iskopira, a ne samo deo. Ovo sad radi za throw Izuzetak("desila se greška"), ali ne radi za throw Izuzetak((string("desila se greška kod pristupanja indeksu ") + indeks).c_str()), jer je u ovom drugom slučaju string privremen i na kraju Izuzetak::p pokazuje na nevažeći deo memorije. I nedostaje ti const za char *s, tako da ne može da se kompajlira linija u kojoj praviš objekat Izuzetak sa const char * parametrom (a svaki string literal "..." je const char *)

Code:
template <class Tip,int N=10,int korak=5>

N i korak treba da budu parametri konstruktora. Vrednost N se menja tokom vremena, tako da ona obavezno mora da bude članica klase. Ne znam šta će se desiti ako imaš Kolekcija<int, 10, 5> i Kolekcija<int, 11, 6>, ali čini mi se da su to za kompajler dve različite klase, i nećeš moći da ih mešaš (preko konstruktora Kolekcija(Kolekcija&)).

Code:
             Kolekcija() { n=-1; podatak=new Tip[N]; }   

-1 vrednost je specijalna vrednost koja ovde nema svrhu. Trebalo bi da stoji 0, jer to znači da je kolekcija prazna. Uostalom Kolekcija::broj_elemenata() ne bi trebalo da vraća -1.

Code:
             Kolekcija( Kolekcija &k) { podatak=new Tip(*k.podatak); } 

Prvo, trebalo bi da parametar k bude const, a drugo ovaj konstruktor kopira samo prvi element niza podatak, a trebalo bi da iskopira sve. Takođe, moraš i dužinu niza da postaviš na odgovarajuću vrednost.

Code:
             Kolekcija &operator=(const Kolekcija &k) {  podatak=k.podatak; return *this; )

Ovo je problem, jer sad imaš dva objekta koji pokazuju na isti niz, i kad se jedan objekat obriše drugi će pokazivati na nepostojeći niz. Moraš da iskopiraš niz i dužinu niza da postaviš na odgovarajuću vrednost (isto kao i kod copy konstruktora, zato bi mogao da napraviš jednu funkciju koja radi posao na dva mesta).

Code:
             Kolekcija &operator+=(const Kolekcija &k)
              {
                   if (n>=N-1) N+=korak;        // ako je kapacitet prepunjen
                   podatak+=k.podatak;
                   return *this; 
              }

Evo razloga zašto N mora da bude članica klase a ne parametar šablona (template). Ovo ne može da se kompajlira jer pokušavaš da promeniš N. U nastavku na pointer podatak dodaješ drugi pointer k.podatak, a to ne može, mislim, šta je rezultat zbira dva pointera? Ono što treba da uradiš je da napraviš novi niz, dovoljno velik, iskopiraš stare podatke, iskopiraš u nastavku nove podatke, obrišeš stari niz, i namestiš podatak da pokazuje na novi niz. Razlog da povećaš kapacitet niza nije ako je n>=N-1 (što ne bi ni trebalo ikad da se desi), nego ako je n+k.n>N. Obrati pažnju da N+=korak mora da bude u petlji jer možda jedan korak nije dovoljan da valjano proširi kapacitet. Znači nije if nego je while.

Code:
template <class Tip,int N=10,int korak=5>
void Kolekcija<Tip,N,korak> :: izvadiPodatak ( Tip &p)
{
     for (int i=0; i<n; i++)
       if (podatak[i]==p) 
         {  for ( int j=i, k=j+1; k<n ; j++,k++)
               podatak[j]=podatak[k];
         }
};

Zaboravio si da smanjiš n svaki put kad pronađeš podatak[ i]==p. Uzgred, postoji i efikasnije rešenje od ovog. Trenutno ti ispomeraš ostatak niza za jedno mesto svaki put kad pronađeš traženu vrednost, ali zamisli da treba da izvadiš broj 5 u nizu {1,2,3,5,5,5,5,6,7,5,5,5,8,9,5,5,5,10}. Ono što bi trebalo da uradiš je samo da preskačeš petice, to jest da 6 odmah iskopiraš na 4. mesto, broj 7 na peto, 8 na šesto, itd. Imao bi jednostruku petlju umesto dvostruke, i minimalan broj kopiranja elemenata.

Code:
          if (indeks>=N-1) throw Izuzetak ("Nekorektan broj pri citanju!\n");

Ovaj if i ovaj throw treba da stoje unutar operatora[], nije im mesto ovde (cilj je da klasa radi za tebe, a ne da ti radiš za klasu). Uostalom, ovo neće da se kompajlira, jer N ovde ne postoji. Znači, ovde ti pokušavaš da pročitaš k[indeks], a po potrebi on diže izuzetak. Drugo, ne treba da proveravaš N nego n jer sve posle n je nevažeće, makar bilo i pre N. Treće, šta ako je indeks==n-1? Desiće se izuzetak bez potrebe. Četvrto, treba da pokriješ i negativne vrednosti. Uslov treba da glasi if (indeks < 0 || indeks >= n).

Code:
     catch ( Izuzetak t )

Nisam 100% siguran, trebalo bi proveriti, ali mislim da ovo neće da se kompajlira jer klasa Izuzetak nema copy konstruktor.
 
Odgovor na temu

[es] :: C/C++ programiranje :: C/C++ za početnike :: genericka klasa Kolekcija - komentari!

[ Pregleda: 1252 | Odgovora: 1 ] > FB > Twit

Postavi temu Odgovori

Navigacija
Lista poslednjih: 16, 32, 64, 128 poruka.