Programmeren in C++/Pointers: verschil tussen versies

Verwijderde inhoud Toegevoegde inhoud
Sephiroth (overleg | bijdragen)
kGeen bewerkingssamenvatting
Pagina leeggehaald door gebruiker
Regel 1:
{{Programmeren in C++}}
{{TeDoen|wat=Onderverdelen in kopjes}}
Pointers behoren tot de krachtigste hulpmiddelen die er zijn in C++. Het werken met pointers is wel tamelijk lastig om te leren, wat gedeeltelijk veroorzaakt wordt door de enigszins verwarrende wijze waarop in C++ variabelen gedeclareerd worden. Zo is:
 
{{Code|
| Taal=C++
| Titel=
| Code=
<source lang="cpp">
int *intPnt
</source>
}}
 
niet de declaratie van een integer met de naam *intPnt, maar de declaratie van een pointer naar een integer met de naam intPnt. De werkelijke achtergrond van deze notatie is echter dat *intPnt wel degelijk een integer is, en juist de integer waar intPnt naar wijst. In dit artikel moet je wel weten wat een variabele is, wat voor types je hebt en hoe je ze aanmaakt.
 
Een pointer is een variabele waar je een geheugenadres in opslaat. Waarschijnlijk moet je de regel een paar keer lezen om hem te snappen, maar ik zal hem hier nog even uitgebreid verklaren. Een pointer is dus een variabele. Dat is een object waarin je gegevens kunt opslaan. In het geval van een pointer sla je dus in die variabele een geheugenadres op.
 
Wat is nou een geheugenadres? Het geheugen is verdeeld in hokken, laten we zeggen postvakjes. Ieder postvakje heeft een uniek adres oftewel een uniek geheugenadres. Ieder postvakje is 1 byte. Zo wordt bijvoorbeeld bij een unsigned long int 4 postvakjes gereserveerd. Een unsigned long int is 4 bytes, dus krijgt hij 4 vakjes toegewezen.
 
Nou hoef je natuurlijk als programmeur niet de adressen van je variabelen te weten. Daar heeft C++ een operator voor. Om achter het adres van een variabele te komen gebruik je de "address of"-operator oftewel &. Om dit te demonstreren is hier een voorbeeld.
 
 
{{Code|
| Taal=C++
| Titel=
| Code=
<source lang="cpp">
#include <iostream>
using namespace std;
 
int main()
{
unsigned short shortVar=5;
 
cout << "shortVar: " << shortVar;
cout << " Adres van shortVar: " << &shortVar << endl;
 
return 0;
}
</source>
}}
 
De uitvoer zou kunnen zijn (verschilt per computer):
{{Code|
| Taal=C++
| Titel=
| Code=
<source lang="cpp">
shortVar: 5 Adres van shortVar: 0x8fc9:fff4
</source>
}}
In dit geval heeft de variabele 'ShortVar' het adres '0x8fc9:fff4'. Dat betekent niets anders dan dat de geheugenplaats '0x8fc9:fff4' (en ook de drie daarop volgende geheugenplaatsen), met de naam 'shortVar' aangesproken kan worden. Dat is voor ons makkelijker dan steeds die hex-getallen te moeten gebruiken.
 
In een geheugenplaats kan ook informatie opgeslagen worden. In 'shortVar' zelf is het getal 5 opgeslagen. Maar we willen ook het adres van shortVar, dus het hex-getal '0x8fc9:fff4' ergens opslaan. Eigenlijk interesseert het ons niet welk hex-getal het is, dat hoeven we niet te weten, het gaat er alleen om dat het het adres van 'shortVar' is. We hebben dus een variabele nodig waarin je zo'n adres kunt opslaan. Zo'n variabele is een ''pointer''.
 
Een voorbeeld.
{{Code|
| Taal=C++
| Titel=
| Code=
<source lang="cpp">
int myAge = 15; // Maakt variabele myAge
int *pAge = 0; // Maakt pointer pAge
 
pAge = &myAge ; // zet het adres van myAge in de pointer pAge
</source>
}}
 
We declareren weer eerst een variabele, nl. 'myAge'. In de tweede regel declareren we een pointer, 'pAge', waarin we het adres van 'myAge' kunnen opslaan. Door het sterretje(*) voor 'pAge' wordt 'pAge' een pointer naar een integer. In de derde regel wordt in de pointer het adres van 'myAge' opgeslagen.
 
Wat kun je hier nou mee? Heel simpel je kunt nu met de pointer pAge, de waarde van myAge ophalen. Dit wordt indirectie genoemd. Let wel op, om de waarde op te halen moet je het sterretje(*) voor de pointer zetten, dus het wordt *pAge. Het sterretje(*) wordt ook wel de indirectie-operator genoemd.
 
In deze tutorial ga ik het hebben over de vrije geheugenruimte, ook wel de heap genoemd. De heap is de ruimte waar variabelen en objecten blijven bestaan tot het moment dat jij ze verwijdert of het programma is beëindigd.
 
Hoe werkt dit nu? Kijk even naar het volgende voorbeeld:
{{Code|
| Taal=C++
| Titel=
| Code=
<source lang="cpp">
int mijnLeeftijd = 18;
int *pLeeftijd = new int;
pLeeftijd = &mijnLeeftijd;
 
cout << *pLeeftijd;
 
</source>
}}
 
Output: 18
 
Wat heb je nu gedaan? Denk er eerst zelf even over na, dan leg ik het uit....
 
We beginnen met het maken van een lokale variabele in de stack, genaamd mijnLeeftijd en geven die de waarde 18.
 
In de vrije geheugenruimte maken we een pointer *pLeeftijd groot genoeg om het adres van een integer op te slaan.
 
Het adres van mijnLeeftijd stoppen we in de pointer *pLeeftijd door middel van de operator & (adress of).
 
Vervolgens geven we de waarde weer die op het opgeslagen adres staat, 18 dus. Dit proces noemen we indirectie.
 
Behalve met variabelen werkt dit proces ook met objecten, zoals een class. Hier volgt een voorbeeld.
{{Code|
| Taal=C++
| Titel=
| Code=
<source lang="cpp">
#include <iostream>
using namespace std;
 
class CSimpleCat
{
public:
CSimpleCat();
~CSimpleCat();
int getAge() const { return *itsAge; }
void setAge(int age) { *itsAge = age; }
 
int getWeight() const { return *itsWeight; }
int setWeight ( int weight) { *itsWeight = weight; }
 
private:
int *itsAge;
int *itsWeight;
};
 
CSimpleCat::CSimpleCat()
{
itsAge = new int(2);
itsWeight = new int(5);
}
 
CSimpleCat::~CSimpleCat()
{
delete itsAge;
delete itsWeight;
}
 
int main()
{
CSimpleCat * pFrisky = new CSimpleCat;
cout << "Frisky is "<< pFrisky->getAge() << " jaar oud" << endl;
pFrisky->setAge(5);
cout << "Frisky is "<< pFrisky->getAge() << " jaar oud" << endl;
delete pFrisky;
return 0;
}
</source>
}}
 
Zo dat ziet er waarschijnlijk een beetje moeilijk uit, no worry. Hier is de uitleg.
 
We maken gewoon een class CSimpleCat met een constructor en een aantal accessorfuncties. Dit moet je allemaal bekend voorkomen.
 
De variabelen zijn ook pointers naar variabelen in de vrije geheugenruimte. Dat hebben we net behandeld en dat snap je nu denk wel.
 
In de main-functie krijgen we wel wat nieuwe dingen; die ga ik nu behandelen.
{{Code|
| Taal=C++
| Titel=
| Code=
<source lang="cpp">
CSimpleCat * pFrisky = new CSimpleCat;
</source>
}}
 
Wat zeggen we hier eigenlijk? In gewoon Nederlands zeggen we: "Maak een pointer van het type CSimpleCat in de vrije geheugenruimte met de naam pFrisky wat een CSimpleCat is". Logisch? Niet echt hè.
 
pFrisky is dus van het zelf gemaakte type CSimpleCat. Nu zorgen we er dus voor dat pFrisky het juiste aantal bytes heeft dat CSimpleCat nodig heeft. De opdracht new CSimpleCat zorgt er echter voor dat het ook echt een CSimpleCat wordt.
 
De eerste CSimpleCat is er dus om geheugen te reserveren, de tweede voor de definitie!
 
Hoe bereik je nu de methoden van CSimpleCat door middel van je pointer? Ook hiervoor moet je indirectie toepassen wat betekent dat je het volgende krijgt:
{{Code|
| Taal=C++
| Titel=
| Code=
<source lang="cpp">
(*pFrisky).getAge();
</source>
}}
 
Omdat dit nogal omslachtig is, heeft men in C++ een verkorte versie gemaakt. De "->"-operator. Dus nu schrijf je:
{{Code|
| Taal=C++
| Titel=
| Code=
<source lang="cpp">
pFrisky->getAge();
</source>
}}
 
Om weer over niet-gebruikt geheugen te kunnen beschikken, moet je geheugenruimte vrijmaken. Dit doe je met delete.Daarmee voorkom je ook memory-leaks.
{{Code|
| Taal=C++
| Titel=
| Code=
<source lang="cpp">
delete pFrisky;
pFriksy = 0;
</source>
}}
 
Waarom zetten we pFrisky op 0? Als je dit niet doet krijg je een zogeheten wilde pointer. Het gevaar hiervan is, dat als je hem nog een keer verwijdert, in het mooiste geval je programma crasht, maar in het ergste geval je een vastloper krijgt.
 
Nu kan je namelijk veilig het volgende doen:
{{Code|
| Taal=C++
| Titel=
| Code=
<source lang="cpp">
int *pInt = new int;
delete pInt;
pInt = 0;
delete pInt;
</source>
}}
 
[[Categorie:Programmeren in C++|Pointers]]
{{GFDL-oud}}
Informatie afkomstig van https://nl.wikibooks.org Wikibooks NL.
Wikibooks NL is onderdeel van de wikimediafoundation.