Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Wiki Markup
h2. 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 5.

Esimerkki 4: Kopiomuodostimen esittely.

class CElain
\{
private:
    float m_Massa;

public:
    CElain() {}              // Tyhjä oletusmuodostin.
    CElain(  const CElain&);   // Kopiomuodostin
};
Yllä olevassa esimerkissä on esitelty kopiomuodostin (ilman  toteutusta). Toteutus voisi olla seuraavanlainen:

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
\{         m_Nimi = new char\[strlen(Nimi) + 1\];    // Varataan muistia, annetun merkkijonon verran.
         }

    ~CElain()
    {
        delete
\{         delete \[\] m_Nimi;                                         // Vapautetaan varattu muisti.
         }

    CElain() { }
    CElain(const CElain& Instanssi)
    {
       
\{         this->m_Massa = Instanssi.m_Massa;
                this->m_Nimi = Instanssi 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.