Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migration of unmigrated content due to installation of a new plugin

...

Muodostimet

...

(Constructor)

...

Aina,

...

kun

...

luodaan

...

uusi

...

olio

...

suoritetaan

...

automaattisesti

...

muodostin-funktio.

...

Lisäksi

...

kutsutaan

...

mahdollisen

...

vanhemman

...

muodostinta,

...

sekä

...

kaikkien

...

olioiden

...

muodostimia,

...

mistä

...

luokka

...

koostuu.

...

Muodostimen

...

nimi

...

on

...

sama

...

kuin

...

luokan

...

nimi. Image Added

Anchor
esim1
esim1

Esimerkki 1. Parametriton muodostin.

Code Block


Esimerkki 1: Muodostin.

{code}
class CElain
{
public:
    CElain();   // Parametriton Muodostinmuodostin
};
{code}

Yllä

...

olevassa

...

esimerkissä

...

on

...

esitelty

...

parametriton

...

muodostin

...

(ilman

...

toteutusta).

...

Muodostimessa

...

voidaan

...

antaa

...

oliolle

...

alkuarvoja,

...

varata

...

muistia

...

jne.

...

Jos

...

muodostimelle

...

halutaan

...

antaa

...

parametreja,

...

laitetaan

...

ne

...

sulkuihin,

...

kuten

...

mihin

...

tahansa

...

funktioon.

...

Muodostin

...

ei

...

palauta

...

mitään,

...

joten

...

nimen

...

eteen

...

ei

...

saa

...

laittaa

...

mitään

...

tyyppiä,

...

ei

...

edes

...

void-määrittelyä.

Anchor
esim2
esim2

Esimerkki 2. Luokkaan CElain on lisätty muodostin, joka antaa luokan oliolle heti nimen ja massan.

Code Block


Esimerkki 2: Luokkaan CElain on lisätty muodostin, joka antaa luokan  oliolle heti nimen ja massan.

class CElain
{
private:
    char    char m_Nimi\[100\];
    float    float m_Massa;

public:
        CElain(char Nimi\[\], float float Massa);   // MuodostinParametrillinen muodostin

    bool    bool AsetaNimi(char Nimi\[\]);
    bool KysyNimi(char Nimi\[\]);

         // Asetusfunktio
    char[] PalautaNimi();             // Palautusfunktio

    bool AsetaMassa(float Massa);
    bool KysyMassa();     // Asetusfunktio
    float PalautaMassa();             // Palautusfunktio
};

Muodostimelle

...

täytyy

...

tehdä

...

vielä

...

toteutus,

...

joka

...

voi

...

olla

...

esim.

...

seuraavanlainen:

Code Block


CElain::CElain(char Nimi\[\], float Massa) // Parametrillinen muodostin
{
    strcpy     strcpy(m_Nimi, Nimi);
    m     m_Massa = Massa;
}

Luokalla

...

on

...

aina

...

oletusmuodostin,

...

esim

...

CElain::CElain(),

...

mutta

...

jos

...

ohjelmoija

...

tekee

...

yhdenkin

...

oman

...

muodostimen

...

ei

...

oletusmuodostinta

...

voida

...

enää

...

käyttää.

...

Yllä

...

olevassa

...

esimerkissä

...

tulisi

...

kaikki

...

CElain-luokan

...

oliot

...

muodostaa

...

antamalla

...

niille

...

nimi

...

ja

...

massa.

...

Esimerkiksi:

Code Block


CElain kissa("misu", 5.2);

Mutta

...

koska

...

oletusmuodostinta

...

ei

...

voida

...

enää

...

käyttää,

...

seuraava

...

ei

...

ole

...

validia

...

koodia:

Code Block

CElain kissa;
Huom\! Jos parametritonta muodostinta halutaan käyttää, tulee myös se  
Note

Jos parametritonta muodostinta halutaan käyttää, tulee myös se lisätä luokkaan:

Code Block

lisätä luokkaan:

class CElain {
...
public:
      CElain();
    CElain(char Nimi\[\], float Massa);
...
\\

h3    CElain();                         // Parametriton muodostin
    CElain(char Nimi[], float Massa); // Parametrillinen muodostin
...

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 3. Kopiomuodostimen esittely.

Code Block

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:

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 4. Kopiomuodostin, kun luokassa on osoittimia.

Code Block

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:

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(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.