Přidat otázku mezi oblíbenéZasílat nové odpovědi e-mailemVyřešeno Pomozte s programem v C++...

Zdravím,
potřebuju tuhle: http://java.sun.com/j2se/1.4.2/docs/api/java/util/A rrayList.html třídu pro C++, asi by nebyl problém si něco takového napsat, ale raději se zeptám jesti už něco takového neexistuje, abych si ušetřil psaní...:-) Nemusí to být úplně stejné alespoň principiálně. Řeším příklad Malý vysokoškolský studijní systém. Rozvrhl jsem si to nějak takto:
1. třída: Osoba
2. třídy: Zaměstnanec, Student - dědí z třídy Osoba
3. třída: Doktorand - dědí z třídy Zaměstnanec i Student (doktorand je v podstatě i zaměstnanec, dostává plat) :-)
4. třída: Zkouška
5. třídy: SeznamStudentů, SeznamZaměstnanců, SeznamZkoušek, SeznamDoktorandů - dětí z třídy ArrayList, a doplním pouze metody, jako např. najdiStudenta(int id), tiskSeznamu() apod.

Každý student a doktorand bude mít privatní atribut kolekci (ArrayList) zkoušek na které se zapsal.

PS: Snad jsem to napsal srozumitelně. Jedná se o projekt k zápočtu z C++...:-) Budu vděčný za každé připomínky k mojí úvaze... Má někdo podobnou třídu, jako je zmiňovaný Javovský ArrayList pro C++ (měla by to být třída, která je Template)?

Díky! :beer:
MaSo

Předmět Autor Datum
Pozri si triedu std::list<T> z STL.
los 30.05.2007 14:49
los
To bude zřejmě ono, díky. Nějak jsem ale nepochopil, jak to dostanu to toho svého programu...:-[ Pou…
MaSo 30.05.2007 15:01
MaSo
Neviem, aký s tým máš problém. Toto ti ide skompilovať? #include <list> int main() { std::list<int>…
los 30.05.2007 19:07
los
:-[ Jsem dneska nějaký pomalejší, ano jde to. Nějak jsem žil v přesvědčení, že si musím někde stáhno…
MaSo 30.05.2007 19:11
MaSo
5. třídy: SeznamStudentů, SeznamZaměstnanců, SeznamZkoušek, SeznamDoktorandů - dětí z třídy ArrayLis…
los 30.05.2007 19:19
los
Díky. A můžu se zeptat proč se chceš vyhnout dědění z Listu? Řešil jsem podobný příklad v Javě a děl…
MaSo 30.05.2007 19:38
MaSo
List v C++ nebol navrhnutý na to, aby sa z neho dedilo. Nemá napr. ani virtuálny deštruktor. Ak chce…
los 30.05.2007 19:46
los
Jak udělat v C++ aby metoda vracela odkaz na null? Mám toto: Student SeznamStudentu :: najdiStudent…
MaSo 01.06.2007 20:59
MaSo
null je 0 resp. presnejsie povedane tusim (void*)0 Delphi ma mozno nil, resp. ma vobec Delphi pointr…
MM.. 01.06.2007 22:13
MM..
Ty voe...:-D Kde si vzal Delphi? Ja se ptam na C++! (Void*)0 jsem nasel googlem, nefachci...:-( To C…
MaSo 02.06.2007 02:15
MaSo
Jaj o Delphi bol dotaz vedla :-D ked to je C++ tak mas normalne zadefinovane NULL, ale ta fcia nevra…
MM.. 02.06.2007 22:36
MM..
NULL je ukazovateľ, zatiaľ čo tvoja funkcia má vrátiť inštanciu triedy Student a nie ukazovateľ na i…
los 02.06.2007 10:09
los
Díky, za obsáhlou odpověď. :beer: 2. Prerobiť zoznam študentov tak, aby obsahoval ukazovatele. V pr…
MaSo 02.06.2007 14:41
MaSo
Keď to prerobíš na ukazovatele, budeš musieť k vlastnostiam a metódam objektu pristupovať cez operát…
los 02.06.2007 21:00
los
Losi, díky moc! :beer: Nevím, co bych si bez tebe počal... Předělal jsem to teda tak, aby seznamy ob…
MaSo 03.06.2007 14:34
MaSo
Po tom ako odstrániš študenta zo zoznamu, nemôžeš ďalej zvyšovať iterátor, takže tam musíš dať break…
los 03.06.2007 17:37
los
Tak hlavně díky tobě, jsem program dokončil. Zítra (vlastně už dneska :-)) ho předvedu u zkoušky, sn…
MaSo 04.06.2007 00:06
MaSo
Tak program se líbil, ale u zkoušky jsem trochu domotal včasnou a pozdní vazbu, takže nakonec za dvě… poslední
MaSo 04.06.2007 10:23
MaSo

5. třídy: SeznamStudentů, SeznamZaměstnanců, SeznamZkoušek, SeznamDoktorandů - dětí z třídy ArrayList, a doplním pouze metody, jako např. najdiStudenta(int id), tiskSeznamu() apod.

Spravil by som to tak, že zoznam študentov, zamestnancov a pod. by som mal v std::list a vyhľadávacie funkcie by boli statické metódy tých tried, aby som sa vyhol dedeniu zo std::list. Čiže by si napr. študenta s nejakým identifikátorom našiel pomocou takejto funkcie:

Student* Student::najdi(int id, std::list<Student*>& zoznam)

Prípadne by si mohol použiť hešovaciu tabuľku (std::map<int, Student*>).

Jak udělat v C++ aby metoda vracela odkaz na null? Mám toto:

Student SeznamStudentu :: najdiStudenta(int id)
{
      list<Student>::iterator i;
     
      for(i=studenti.begin(); i != studenti.end(); ++i)
      {
       if ((*i).getId() == id) return (*i);
      }
      return null; // toto samozdrejme neprojde kompilaci :-(, tohle jsem si pujcil z Javy :-)
}

Když se student nenajde, tak chci vrátit null. Ví někdo, jak na to?

Ty voe...:-D Kde si vzal Delphi? Ja se ptam na C++! (Void*)0 jsem nasel googlem, nefachci...:-( To C++ je nějaké divné, to co, jde v Javě na dva řádky, aby tam (v C++) člověk psal v Assembleru...:-D

Napadly mě HCéčka, jako vracet nějakého fake Studenta, který má id třeba -99, ale to se mi zdá velmi amatérské... Takový program, by byl fakt přátelský na paměť, kbyby při každém vyhledávaní vytvářel nové objekty...:-D... Co kdyby, se vyhledávalo třeba milionkrát...:-D

Null myšleno jako odkaz na nic...

NULL je ukazovateľ, zatiaľ čo tvoja funkcia má vrátiť inštanciu triedy Student a nie ukazovateľ na inštanciu.

Riešení je viacero:
1. Použiť namiesto triedy std::list triedu std::map, ktorá má funkciu pre hľadanie podľa kľúča.
2. Prerobiť zoznam študentov tak, aby obsahoval ukazovatele. V prípade neúspechu sa vráti NULL.
3. Zmeniť vyhľadávaciu funkciu tak, aby vrátila iterátor. V prípade neúspechu sa vráti studenti.end().
4. Použiť vzor Null Object. V prípade neúspechu sa vráti nejaká dohodnutá inštancia, reprezentujúca žiadneho študenta.

Edit: Asi si už na to prišiel, ale pre istotu: Ak máš kontajner (std::list, std::map, ...), do ktorého vkladáš priamo inštancie nejakej triedy a nie ukazovatele, tak tá trieda musí implementovať minimálne kopírovací konštruktor, aby to vôbec fungovalo.

Díky, za obsáhlou odpověď. :beer:

2. Prerobiť zoznam študentov tak, aby obsahoval ukazovatele. V prípade neúspechu sa vráti NULL.

Když to předělám na ukazatele, budu moc při procházení seznamem volat metody? Např.:

void SeznamStudentu :: vypisSeznam()
{
     list<Student>::iterator i;
      for(i=studenti.begin(); i != studenti.end(); ++i)
      {
        (*i).vypisStudenta();
      }
}

Nějak mi taky neleze do hlavy jak ten seznam zadefinovat, aby obsahoval pointery... Zřejmě takto:

std::list<Student*> studenti

Ale jak pak udělat metodu přidej studenta? Teď to mám takhle:

void SeznamStudentu :: pridejStudenta(Student s)
{
     studenti.push_back(s);
     pocetStudentu++;
}

4. Použiť vzor Null Object. V prípade neúspechu sa vráti nejaká dohodnutá inštancia, reprezentujúca žiadneho študenta.

Tohle se mi zamlouvá... viz: http://blog.vyvojar.cz/lazo/archive/2005/06/20/6177 .aspx

Keď to prerobíš na ukazovatele, budeš musieť k vlastnostiam a metódam objektu pristupovať cez operátor -> namiesto obyčajnej bodky. Takže ten kód bude vyzerať nejako takto:

void SeznamStudentu::vypisSeznam() {
  list<Student*>::iterator i;

  for (i = studenti.begin(); i != studenti.end(); ++i)
    (*i)->vypisStudenta();
}

A ďalej:

void SeznamStudentu::pridejStudenta(Student* s) {
     studenti.push_back(s);
     ++pocetStudentu; // pocetStudentu == studenti.size()
}

Použitie:

Student* s = new Student();
seznamStudentu.pridejStudenta(s);

Študentov potom samozrejme treba niekedy uvoľniť z pamäte.

Použitiu Null objektu by som sa vyhol, ak na to nemáš nejaký pádny dôvod (.šámeN).

Losi, díky moc! :beer: Nevím, co bych si bez tebe počal... Předělal jsem to teda tak, aby seznamy obsalovaly pointery, ale ještě se mi nepodařilo zprovoznit odebrání studenta ze seznamu na základě jeho id...:-(

Napadly mě dvě varianty, bohužel ani jedna mi nepracuje...
1.

void SeznamStudentu :: odeberStudenta(int id)
{
     list<Student*>::iterator i;
     for(i=studenti.begin(); i != studenti.end(); i++)
      {
       if (((*i)->getId()) == id) studenti.remove((*i));
      }
}

2.

void SeznamStudentu :: odeberStudenta(int id)
{
     list<Student*>::iterator i;
     for(i=studenti.begin(); i != studenti.end(); i++)
      {
       if (((*i)->getId()) == id) studenti.erase(i));
      }
}

Program jde normálně zkompilovat, ale když se pokusím zavolat metodu na odebrání, končím na Windows hlášce, že program provedl neplatnou operaci...:-|

PS: V metodách ještě nemám zohledněné co dělat když se student s daným id nenajde... To dodělám, až mi to bude chodit aspoň takhle.

PSS:
Medota najdiStudenta(int id) mi jede, nedalo by se ji nějak využit při odebíraní?

Student* SeznamStudentu :: najdiStudenta(int id)
{
     list<Student*>::iterator i;
     for(i=studenti.begin(); i != studenti.end(); i++)
      {
       if (((*i)->getId()) == id) return (*i);
      }
      return NULL;
}

Javě by to šlo napsat třeba takto:

 public void odeberStudenta(int id)
 {
    Student s;
    ListIterator <Student> i = studenti.listIterator();
    while(i.hasNext())
      {
        s = (Student)i.next();
        if (s.getId() == id)
        {   
           studenti.remove(studenti.indexOf(s));
        }
        else System.out.println("Student s ID "+id+" nenalezen"); // vyjimka by byla asi lepsi
      }
}

Po tom ako odstrániš študenta zo zoznamu, nemôžeš ďalej zvyšovať iterátor, takže tam musíš dať break. Debugger by ti mal ukázať presne, kedy to spadne.

void SeznamStudentu::odeberStudenta(int id) {
  list<Student*>::iterator i;

  for (i = studenti.begin(); i != studenti.end(); ++i)
    if ((*i)->getId() == id) {
      studenti.erase(i);
      break;
    }
}

Zpět do poradny Odpovědět na původní otázku Nahoru