...
Hajoittimet
...
(Destructor)
...
Hajoittimen
...
nimi
...
on
...
muotoa
...
mato(~)
...
ja
...
sen
...
perään
...
luokan
...
nimi,
...
esim.
...
~CElain().
...
Hajoittimen
...
ominaisuuksia:
...
- Hajoittimessa
...
- tulee
...
- vapauttaa
...
- muodostimessa
...
- varatut
...
- muistit.
...
- Kutsutaan
...
- automaattisesti,
...
- kuten
...
- muodostintakin.
...
- Hajoittimelle
...
- ei
...
- voi
...
- antaa
...
- parametreja.
...
- Vaikka
...
- muodostin
...
- on
...
- ylikirjoitettu,
...
- voidaan
...
- silti
...
- käyttää
...
- oletushajoitinta.
...
Kopiomuodostimet
...
(Copy
...
Constructor)
...
Kopiomuodostin
...
on
...
muodostin,
...
jolle
...
annetaan
...
parametrina
...
referenssi
...
itsensä
...
tyyppiseen
...
olioon.
...
Kopiomuodostimen
...
idea
...
on
...
mahdollistaa
...
olion
...
monistaminen
...
eli
...
kopioiminen.
...
C+
...
+
...
tarjoaa
...
oletuskopiomuodostimen
...
joka
...
osaa
...
tehdä
...
matalan
...
kopioinnin
...
(shallow
...
copy),
...
tarkoittaen
...
että
...
se
...
kopioi
...
kaikkien
...
jäsenmuuttujien
...
arvot,
...
myös
...
osoittimien,
...
mikä
...
on
...
ongelma,
...
kts.
...
Esimerkki 2.
Esimerkki 1: Kopiomuodostimen esittely.
Code Block |
---|
5. h2. Esimerkki 4: Kopiomuodostimen esittely. {code} class CElain { private: float m_Massa; public: CElain() {} // Tyhjä oletusmuodostin. CElain(const CElain&); // Kopiomuodostin }; {code} |
Yllä
...
olevassa
...
esimerkissä
...
on
...
esitelty
...
kopiomuodostin
...
(ilman
...
toteutusta).
...
Toteutus
...
voisi
...
olla
...
seuraavanlainen:
Code Block |
---|
} CElain::CElain( const CElain& Instanssi) { this->m_Massa = Instanssi.m_Massa; // Kopioidaan annetun olion muuttujan m_Massa arvo omaamme. } |
Yllä
...
annettu
...
toteutus
...
on
...
itse
...
asiassa
...
sama
...
kuin
...
oletuskopiomuodostin.
...
Se
...
kopioi
...
kaikkien
...
jäsenmuuttujien
...
arvot.
...
Esimerkki
...
2:
...
Kopiomuodostin,
...
kun
...
luokassa
...
on
...
osoittimia.
Code Block |
---|
class CElain { private: float m_Massa; char* m_Nimi; // Osoitin. public: CElain(char Nimi[]) { m { m_Nimi = new char[strlen(Nimi) + 1]; // Varataan muistia, annetun merkkijonon verran. } ~CElain() \{ delete \[\ } ~CElain() { delete [] m_Nimi; // Vapautetaan varattu muisti. } CElain() { } CElain(const CElain& Instanssi) \{ { this->m_Massa = Instanssi.m_Massa; this->m_Nimi = Instanssi.m_Nimi; // Tässä kopioidaan ainoastaan osoittimen arvo, ei itse muistia\! } }; |
Yllä
...
oleva
...
kopiomuodostin
...
(joka
...
siis
...
on
...
kuten
...
oletuskopiomuodostin)
...
aiheuttaa
...
ongelmia.
...
Ajatellaan
...
seuraavaa
...
tilannetta:
...
- Luodaan
...
- ensimmäinen
...
- olio,
...
- sille
...
- annetaan
...
- nimi
...
- ja
...
- varataan
...
- muodostimessa
...
- tarvittavan
...
- määrän
...
- muistia
...
- nimeä
...
- varten.
...
- Luodaan
...
- toinen
...
- olio,
...
- käyttämällä
...
- kopiomuodostinta,
...
- antamalla
...
- ensimmäinen
...
- olio
...
- parametrina.
...
- Nyt
...
- molemmat
...
- oliot
...
- omaavat
...
- saman
...
- massan
...
- ARVON
...
- ja
...
- saman
...
- osoittimen
...
- ARVON
...
- muistiin,
...
- jossa
...
- sijaitsee
...
- nimi.
...
- Siis
...
- molemmat
...
- oliot
...
- osoittavat
...
- samaan
...
- muistialueeseen.
...
- Tuhotaan
...
- ensimmäinen
...
- olio,
...
- jolloin
...
- kutsutaan
...
- sen
...
- hajoitin,
...
- joka
...
- vapauttaa
...
- varatun
...
- muistin.
...
- Nyt
...
- meillä
...
- on
...
- enään
...
- toisena
...
- luoto
...
- olio,
...
- jonka
...
- m_Nimi
...
- osoittaa
...
- muistiin,
...
- joka
...
- juuri
...
- vapautettiin
...
- !
...
- -->
...
- Meillä
...
- on
...
- katastrofi
...
- käsissä
...
- !
...
Yllä
...
kuvatun
...
ongelman
...
välttämiseksi
...
voimme
...
kirjoittaa
...
oman
...
kopiomuodostimen,
...
jossa
...
suoritetaan
...
syvä
...
kopiointi
...
(deep
...
copy),
...
eli
...
varataan
...
tarvittava
...
muisti
...
ja
...
kopioidaan
...
merkkijono
...
sinne:
Code Block |
---|
class CElain { ... CElain(CElain& Instanssi) { { this->m_Massa = Instanssi.m_Massa; this->m_Nimi = new char[strlen(Instanssi.m_Nimi) + 1]; // Varataan tarvittava muisti merkkijonolle. strcpy strcpy(this->m_Nimi, Instanssi.m_Nimi); // Tässä kopioidaan merkkijono. } }; |
Tämä
...
kopiomuodostin
...
kopioi
...
osoittimen
...
sisältämän
...
muistin
...
oikein.
...
Nyt
...
voidaan
...
muodostaa
...
haluttu
...
määrä
...
kopioita
...
ja
...
ne
...
käyttäytyvät
...
kuten
...
pitääkin.