...
Hajoittimet
...
(Destructor)
...
Hajoittimen
...
nimi
...
on
...
muotoa
...
mato(~)
...
ja
...
sen
...
perään
...
luokan
...
nimi,
...
esim.
...
~CElain().
Esimerkki 1. Yksinkertainen hajoitin
Code Block |
---|
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. h3. 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 5. h2. Esimerkki 4: Kopiomuodostimen esittely. {code} class CElain { private: float m_Massa; public: CElain() {} // Tyhjä oletusmuodostin. CElain(const CElain&); ~CElain(); // KopiomuodostinHajoitin }; {code} Yllä olevassa esimerkissä on esitelty kopiomuodostin (ilman toteutusta). Toteutus voisi olla seuraavanlainen: {code} 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 5: Kopiomuodostin, kun luokassa on osoittimia. class CElain {private: float m_Massa; char* m_Nimi; // Osoitin. public: CElain(char Nimi[]) { m_Nimi = new char[strlen(Nimi) + 1]; // Varataan muistia, annetun merkkijonon verran. } ~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: 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(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 |
Hajoittimen toteutus:
Code Block |
---|
class CElain::~CElain()
{
// Tänne koodit
}
|
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.