Toon posts:

[C++] pointers naar objecten uit een list halen

Pagina: 1
Acties:

Verwijderd

Topicstarter
Ik zit met het volgende probleem:
Ik ben met een programma bezig waar onderandere een klantbeheer in zit.
Elke klant word aangemaakt vanuit het object klantenbeer en word in een list gezet dmv de volgende code:
code:
1
2
3
list<Klant> klantenlijst; //declaratie van de lijst
Klant obj_klant; //nieuwe klant met de naam obj_klant
klantenlijst.push_back(obj_klant); // voeg pointer naar object toe aan de lijst (hier gaat het denk ik fout)


Nu zou ik later klanten weer willen ophalen, er op zoeken of allemaal weer geven. Dit moet via de pointers in de lijst klantenlijst dmv een iterator (correct me if i'm wrong)
ik heb al het volgede stukje code:
code:
1
2
3
4
5
list<Klant>::iterator theIterator;
        for( theIterator = klantenlijst.begin(); theIterator != klantenlijst.end(); theIterator++ ) {
                //cout << *theIterator;
                cout << *; //geeft sterretjes om te kijken of hij de lijst goed doorloopt
        }


Maar hoe kom ik via die pointer dan terug bij mijn object inclusief eigenschappen en functies?

[ Voor 11% gewijzigd door Verwijderd op 11-03-2005 01:25 ]


  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

*theIterator is gewoon je object. Dus (*theiterator).foo(); Haakjes hoeven geloof ik niet, maar is wel zo duidelijk. En als er pointers in de lijst staan (wat hier niet zo is?) dan is het (*theIterator)->foo();. Overigens kan je beter ++theIterator doen, is iets sneller, want het scheelt waarschijnlijk een kopie.

Verwijderd

Topicstarter
Het lijkt alsof de lijst geen pointers bevat.
Ik denk dat ik de lijst verkeerd declareer. Doe ik dit wel goed?
Het probleem is dat ik heel weinig info kan vinden over lijsten met betrekking op pointers naar objecten.

[ Voor 71% gewijzigd door Verwijderd op 11-03-2005 01:23 ]


  • schoene
  • Registratie: Maart 2003
  • Laatst online: 09-05 14:00
C++:
1
2
3
list<Klant> klantenlijst; //declaratie van de lijst
Klant obj_klant; //nieuwe klant met de naam obj_klant
klantenlijst.push_back(obj_klant); // voeg pointer naar object toe aan de lijst (hier gaat het denk ik fout)


Hier voeg je ook geen pointers toe aan je lijst, maar een kopie van obj_klant.
(Tenzij Klant een typedef is als pointer naar een andere klasse, maar dan zou
het helemaal verkeerd zijn, aangezien obj_klant dan niet geinitialiseerd wordt)

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 09-04 22:08
Ten eerste: een class Klantenbeheer is vrijwel zeker slecht ontwerp ("god class").

Ten tweede, de lijst bevat inderdaad geen pointers. Dat is goed, pointers maken het maar ingewikkeld.
Je kunt nu met theIterator->foo( ) methoden aanroepen van elke Klant. (Of, zoals Zoijar zegt, (*theIterator).foo( ) maar dat vind ik minder duidelijk).

Een iterator is een soort pointer die langs de elementen van de lijst wandelt, en in zo'n loop
naar alle elementen van de lijst wijst.

P.S.
C++:
1
std::copy( klantenlijst.begin(), klantenlijst.end(), std::ostream_iterator(std::cout) );

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 23:42

.oisyn

Moderator Devschuur®

Demotivational Speaker

Zoijar schreef op vrijdag 11 maart 2005 @ 00:06:
Dus (*theiterator).foo(); Haakjes hoeven geloof ik niet, maar is wel zo duidelijk.
De haakjes moeten in je voorbeeld wel degelijk, anders dereference je het resultaat van foo() die op theIterator wordt aangeroepen (en dus hoogstwaarschijnlijk niet bestaat ;)). Maar theIterator->foo(); is een wat vaker gebruikte notatie :)

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Verwijderd

Topicstarter
Ik heb nu dit:
code:
1
2
3
4
list<Klant>::iterator theIterator;
        for( theIterator = klantenlijst.begin(); theIterator != klantenlijst.end(); ++theIterator ) {
                         cout << (*theIterator).getVoornaam(); // << "     " << (*theIterator).getVoornaam() << "   " << (*theIterator).getAchternaam() << endl;
                 }


maar als ik het object wijzig blijven deze gegevens hetzelfde. Dit is dus waarschijnlijk zoals hierboven beschreven omdat er een copy van het object in de lijst word bewaard. Ik wil dat de lijst pointers naar de objecten bevat zodat als ik het object aanpas ik niet met een oude copy in mijn lijst zit. Hoe zou in dan mijn list moeten declareren?

  • MrBucket
  • Registratie: Juli 2003
  • Laatst online: 29-10-2022
Verwijderd schreef op vrijdag 11 maart 2005 @ 11:18:
Ik heb nu dit:
code:
1
2
list<Klant>::iterator theIterator;
-knip-


maar als ik het object wijzig blijven deze gegevens hetzelfde. Dit is dus waarschijnlijk zoals hierboven beschreven omdat er een copy van het object in de lijst word bewaard. Ik wil dat de lijst pointers naar de objecten bevat zodat als ik het object aanpas ik niet met een oude copy in mijn lijst zit. Hoe zou in dan mijn list moeten declareren?
Je zou eventueel een lijst van pointers kunnen gebruiken (dus list<Klant *>), maar dan moet je zelf de objecten die uit de lijst worden verwijderd deleten. Immers, je wist dan alleen een pointer uit de lijst, niet het object waarnaar verwezen wordt.

Maar wat je zegt klopt niet helemaal. Als je dmv een iterator een functie aanroept op een object in je lijst, dan wordt het object in de lijst wel degelijk veranderd (en niet een kopie ervan). Als je een iterator dereferenced krijg je namelijk geen kopie terug van het object, maar een reference naar het object in je lijst.

Dit zou bijvoorbeeld gewoon moeten werken:
C++:
1
2
3
4
5
std::list<int> myList;
myList.push_back(5);

std::list<int>::iterator it = myList.begin();
(*it)++;   //Maakt het enige element in de list nu 6.


--edit--
Oh wacht, ik denk dat ik weet waar jij de mist ingaat. Als je een Klant uit je lijst wil veranderen, moet je:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
list<Klant>::iterator it;

//Niet dit doen - dan maak je een kopie van (*it), en worden de wijzigingen
//dus op de kopie uitgevoerd ipv op het object in je lijst.
Klant k = *it;
k.setAchternaam("bla");

//Maar dit doen - je maakt geen kopie van (*it), maar je werkt rechtstreeks
//op het object wat aangewezen wordt door *it.
Klant *pk = &(*it);
pk->setAchternaam("bla");

//Alternatief op naked pointers - references. Dit heeft hetzelfde effect als
//het voorbeeld met pointers. Dit gaat dus ook goed.
Klant &k = *it;    //GEEN kopie maar een verwijzing naar het object in de lijst
k.setAchternaam("bla");

[ Voor 24% gewijzigd door MrBucket op 11-03-2005 11:41 ]


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 09-04 22:08
MrBucket schreef op vrijdag 11 maart 2005 @ 11:30:
[...]

Je zou eventueel een lijst van pointers kunnen gebruiken (dus list<Klant *>), maar dan moet je zelf de objecten die uit de lijst worden verwijderd deleten. Immers, je wist dan alleen een pointer uit de lijst, niet het object waarnaar verwezen wordt.
Nee, niet dus. De list is alleen maar een verwijzing naar objecten die ergens anders staan. Als je die delete, dan mol je dus de originelen.

Evengoed wil de TS geen pointers in de list hebben. De simpele OO reden: pointers breken encapsulation. Het object wat de klantenlijst bevat is de enige die daar veranderingen in mag aanbrengen. Andere classes moeten met hun fikken van Klanten afblijven, en mogen het alleen aan de container vragen.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • MrBucket
  • Registratie: Juli 2003
  • Laatst online: 29-10-2022
MSalters schreef op vrijdag 11 maart 2005 @ 12:48:
[...]

Nee, niet dus. De list is alleen maar een verwijzing naar objecten die ergens anders staan. Als je die delete, dan mol je dus de originelen.
Welke 'die'? Als je de originelen delete, dan wijzen je pointers in de list dus naar een stuk ongeldig geheugen. Als je pointers uit de list erase()d, blijft het object zelf nog wel in het geheugen staan.
Als de pointer in de list je enige pointer naar dat object was, dan kan je dat object dus nooit meer deleten.
Evengoed wil de TS geen pointers in de list hebben. De simpele OO reden: pointers breken encapsulation. Het object wat de klantenlijst bevat is de enige die daar veranderingen in mag aanbrengen. Andere classes moeten met hun fikken van Klanten afblijven, en mogen het alleen aan de container vragen.
Dan moet je dus wel alle methoden die Klant definieert, opnieuw definieren in Klantenlijst. Lijkt me niet handig, en bovendien heb je in de meeste gevallen niet zoveel controle nodig op de objecten die de Klantenlijst bevat. De list zal niet uit elkaar vallen als je iemand z'n postcode wijzigt.

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 09-04 22:08
MrBucket schreef op vrijdag 11 maart 2005 @ 13:08:
[...]
Dan moet je dus wel alle methoden die Klant definieert, opnieuw definieren in Klantenlijst. Lijkt me niet handig, en bovendien heb je in de meeste gevallen niet zoveel controle nodig op de objecten die de Klantenlijst bevat. De list zal niet uit elkaar vallen als je iemand z'n postcode wijzigt.
Schijn bedriegt.

Postcodes veranderen niet zomaar. Als een straat een nieuwe postcode krijgt, heeft dat consequenties voor alle klanten daar. Als een klant verhuist, dan veranderen alle adresgegevens van die klant. Bovendien, als een klantenlijst object een speciale index heeft om de methode GetKlantenInPostcode( ) te optimaliseren, dan MOET dat klantenlijst object weten wanneer een postcode verandert.

In het meest simpele geval is de code van klantenlijst.nieuwePostcode( klantID ):
C++:
1
2
3
4
5
class Klantenlijst {
typedef std::list<Klant>::iterator klantID;
nieuwePostcode( klantID id, postcode pc ) {
  id->nieuwePostcode(pc);
}

Triviaal.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein

Pagina: 1