Olio-ohjelmointi

Tässä harjoituksessa kerrataan mitä tarkoittavat termit muistiosoite ja osoitin l. pointteri. Lisäksi tutustutaan uuteen käsitteeseen referenssi.

C++-ohjelmoinnissa referenssi on viittaus olemassa olevaan muuttujaan. Se toimii aliaksena, eli referenssi ja alkuperäinen muuttuja viittaavat samaan muistipaikkaan. Referenssi määritellään käyttämällä &-operaattoria. Referensseillä on seuraavat ominaisuudet:

  • Ne on sidottava alustuksen yhteydessä, eikä niitä voi vaihtaa viittaamaan toiseen muuttujaan myöhemmin.
  • Käyttämällä referenssiä voidaan välttää kopioimasta suuria tietorakenteita funktioiden parametreissa.
  • Kaikki muutokset referenssin kautta vaikuttavat alkuperäiseen muuttujaan.
Esimerkki:
 
    int a = 10; 
    int &ref = a; // ref on viittaus muuttujaan a 
    ref = 20; // nyt myös a on 20 

    int *pointer=&a;
    *pointer=30; // nyt myös a on 30
Referenssejä käytetään usein funktioiden parametreina ja palautusarvoina tehokkuuden parantamiseksi.

Harjoitus5

HUOM! Luo kullekin luokalle erillinen h-tiedosto ja cpp-tiedosto.

Osoitin

  1. Luo uusi C++ sovellus
  2. Luo mainissa int muuttuja a ja anna arvoksi 5
  3. Tulosta muuttujan a ja osoite, jolloin tuloksena tulisi olla jotain tällaista:
    a:n arvo on: 5 ja osoite on: 0x5449fff84c
    

  4. Lisää osoitinmuuttuja pointerA ja sijoita siihen muuttujan a osoite ja
    • Tulosta osoittimen osoittaman muistipaikan osoite
    • Tulosta osoittimen osoittaman muistipaikan sisältö
    Nyt tuloksena pitäisi olla jotain tällaista:
    Pointterin osoittama osoite on: 0xb821dff67c
    Pointterin osoittaman muistipaikan arvo on: 5
    


Referenssi

  1. Luo referenssi nimeltään refA ja laita se viittaamaan muuttujaan a ja
    • Tulosta refA:n osoittama osoite
    • Tulosta refA:n osoittaman muistipaikan sisältö
  2. Suorita sovellus jolloin tuloksena pitäisi olla jotain tällaista:
      refA osoittaa osoitteeseen on: 0xc8139ff8bc
      refA:n osoittaman muistipaikan arvo on: 5
      

  3. Lisää muuttuja int muuttuja b ja anna sen arvoksi 6.
  4. Kokeile voitko muuttaa refA:n osoittamaan b:n osoitteeseen?
  5. Kokeile voitko muuttaa pointerA:n osoittamaan b:n osoitteeseen?

Nyt sinun tulisi havaita mitä eroa on seuraavilla:

  • pointerA ja *pointerA
  • refA ja &refA
Ja lisäksi voit havaita, että pointterin voi myöhemmin asettaa osoittamaan eri muistipaikkaan, mutta referensille alustettua osoitetta ei voi vaihtaa.


Olio argumenttina

  1. Lisää sovellukseen luokka ClassB, ja siihen
    1. private string muuttuja nimeltään info
    2. get ja set metodit muuttujalle info
  2. Lisää sovellukseen luokka ClassA1, jonka h-tiedostossa koodi:
    class ClassA1
    {
    private:
        ClassB objectB;
    public:
        ClassA1(ClassB); //Luodaan kopio ClassB-luokan oliosta
        string getBinfo();
        void setBinfo(string);
    };
    
    Ja cpp-tiedostossa koodi:
    ClassA1::ClassA1(ClassB value):objectB(value)
    {
    }
    
    string ClassA1::getBinfo()
    {
        return objectB.getInfo();
    }
    
    void ClassA1::setBinfo(string value)
    {
        objectB.setInfo(value);
    }
    
  3. Lisää main.cpp tiedostoon koodi:
    ClassB objB;
    objB.setInfo("Olion B asettama info");
    
    ClassA1 objA1(objB);
    objA1.setBinfo("Olion objA1 asettama info");
    
    cout<<"objB: "<<objB.getInfo()<<endl;
    cout<<"objA1: "<<objA1.getBinfo()<<endl;
    
  4. Suorita sovellus ja tutki tuloksia
Edellisen vaiheen tarkoitus on havainnollistaa, että alkuperäisen B-olion data ei muutu, vaikka muokkaat A1-olion dataa.

Referenssi argumenttina

  1. Lisää edelliseen tehtävään luokka ClassA2, joka h-tiedostossa koodi:
    class ClassA2
    {
    private:
        ClassB &refB;
    public:
        ClassA2(ClassB&); //Annetaan argumenttina B-luokan olion osoite
        string getBinfo();
        void setBinfo(string);
    };
    
    Ja cpp-tiedotosssa koodi:
    ClassA2::ClassA2(ClassB &value):refB(value)
    {
    }
    
    string ClassA2::getBinfo()
    {
        return refB.getInfo();
    }
    
    void ClassA2::setBinfo(string value)
    {
        refB.setInfo(value);
    }
    
  2. Lisää main.cpp tiedostoon rivit:
    ClassB &refB=objB;
    ClassA2 objA2(refB);
    objA2.setBinfo("Olion Agr asettama info");
    cout<<"objB: "<<objB.getInfo()<<endl;
    cout<<"objA2 "<<objA2.getBinfo()<<endl;
    cout<<endl;
    
  3. Suorita sovellus ja tutki tuloksia.

Edellisen vaiheen tarkoitus on havainnollistaa, että myös alkuperäisen B-olion data muuttuu, kun muokkaat A2-olion dataa.

Tehtävässä voidaan siis havaita, että kun oliolle A annetaan argumenttina olio B, niin A ei voi vaikuttaa olion B dataan.
Jos oliolle A annetaan argumenttina olion B osoite, niin A:n muokkaus muuttaa B:n dataa.

Viittaukset vs. Osoittimet C++:ssa
Ominaisuus Referenssi Osoitin
Määritelmä Referenssi on alias olemassa olevalle muuttujalle. Osoitin tallentaa muuttujan muistiosoitteen.
Tyhjä arvo Ei voi olla tyhjä. Voi olla tyhjä (nullptr).
Uudelleensijoitus Ei voi viitata toiseen muuttujaan alustuksen jälkeen. Voi osoittaa toiseen muistiosoitteeseen.
Yksinkertaisuus Helppokäyttöisempi ja luettavampi. Vaatii tarkempaa käsittelyä.
Käyttötarkoitus Paras yksinkertaisiin tapauksiin, kuten funktioparametreihin ja palautusarvoihin. Paras dynaamiseen muistiin, tyhjiin arvoihin ja matalan tason operaatioihin.
Muistiosoitteiden käyttö Viittaa implisiittisesti objektin muistiosoitteeseen. Sisältää eksplisiittisesti objektin muistiosoitteen.

Suositus: Käytä viittauksia aina kun mahdollista yksinkertaisuuden ja turvallisuuden vuoksi. Käytä osoittimia, kun tarvitaan joustavuutta tai dynaamista muistinhallintaa.



Toggle Menu