Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Wiki Markup
h2. Moniperiytyminen

Tyypillisesti luokka periytyy suoraan ainoastaan yhdestä luokasta,  mutta joskus luokka kannattaa periyttää useista luokista. Kyseessä on  silloin moniperiytyminen.

Esimerkiksi, jos ajattelemme pegasusta, lentävää hevosta, joka omaa ominaisuuksia hevosesta ja  linnusta. Helpoin tapa toteuttaa edellä kuvattu luokka on periyttää sen  ominaisuudet kahdesta luokasta: hevonen ja lintu.

Esimerkki 3. Moniperiytyminen.

class CHevonen
{
    void Aantele() {

    {

    printf("Iii-haa-haa\!\n");
 
   }

\};\\

class CLintu
{
public:
    void Lenna() {
       
{         printf("Lintu lentää\n");
        }
};
\\

class CPegasus :
      public CHevonen,
    public CLintu
{
};

int main()
{
    CPegasus pegasus;

    pegasus.Aantele();
    pegasus.Lenna();
}
Nyt lentävä hevonen perii sekä hevosen että linnun piirteet.

Yksi ongelma moniperiytymisessä tulee vastaan, jos molemmilla  perittävillä luokilla on samanniminen metodi. Esimerkiksi Syo()-metodi.

Esimerkki 4. Moniperiytymisen ongelma.

class CHevonen
{
public:
      void Syo() {
   
{     }
};

class CLintu
{
public:
         void Syo() {
        }
}
};
\\

class CPegasus :
    public CHevonen,
    public CLintu
{
};

int main()
{
    CPegasus pegasus;

    pegasus.Syo();
}
Yllä olevassa esimerkissä C++-kääntäjä ei tiedä kumpaa  Syo()-funktiota tarkoitetaan ja se antaa virheilmoituksen.

Ongelma voidaan kiertää määrittelemällä   kumpaa Syo()-metodeista halutaan käyttää:

int main()
{
    CPegasus pegasus;

    pegasus.  CLintu::Syo();
}

h3. *Moniperintä ohjelmointikielissä*

Kaikki olio-ohjelmointikielet eivät tue moniperintää, kuten esim  Java. Moniperintä on tuettu C++-kielessä.


----
Abstraktit luokat

Yksi olio-ohjelmoinnin perusajatuksista on abstrahointi  (abstraction), eli asioiden käsitteleminen abstraktilla tasolla. 

Esimerkki 1: Abstrakti luokka.

class CElain
{
public:
    virtual \~CElain() {}          // Toteutus tulee olla (tyhjäkin käy).
      virtual void Aantele() = 0;   // Aito virtuaalifunktio .
};
Yllä esitellään luokka CElain, jossa on yksi aito virtuaalifunktio, Aantele(). Tämä tarkoittaa, että CElain  luokasta ei voida luoda oliota. Aantele()-metodin toteutus tulee olla  toteutettuna perivässä luokassa.

Esimerkki 2: Abstraktin luokan toteuttava luokka.

class CKissa : public CElain
{
public:
    void Aantele() {
       
{         printf("Miau\!\n");
        }
};
Tässä peritään CElain-luokka ja toteutetaan sen aito virtuaalifunktio  Aantele().
\\

Abstraktien luokkien käsittely

Abstrakteista luokista ei voida luoda olioita, ainoastaan niiden  perillisistä (olettaen, että ne eivät ole abstrakteja), joita myös  kutsutaan toteuttaviksi luokiksi. Abstraktit luokat toimivat  rajapintana (interface) toteuttavalle luokalle. Kts polymorfismi.

Esimerkki 3: Olioiden käsittely abstraktin (kanta)luokan avulla.

\#include <iostream>

using namespace std;

// Abstrakti luokka, eli kantaluokka.
class CElain
{
public:
&nbsp;&nbsp;&nbsp; virtual \~CElain() {}   &nbsp; &nbsp;// Toteutus tulee olla (tyhjäkin käy).
&nbsp;&nbsp;&nbsp; virtual void Syo() = 0;   // Aito virtuaalifunktio .
};

// CElain-kantaluokan toteuttava luokka.
class CKissa : public CElain
{
public:
&nbsp;&nbsp;&nbsp; void Syo() {
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
{         cout << "Kissa syo kalaa...\n";
&nbsp;&nbsp;&nbsp;     }
};
\\

// CElain-kantaluokan toteuttava luokka.
class CKoira : public CElain
{
public:
&nbsp;&nbsp;&nbsp; void Syo() {
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
{         cout << "Koira syo lihaa...\n";
&nbsp;&nbsp;&nbsp;     }
};
\\

// Luokka johon voidaan tuoda CElain-luokan perillisiä.
class CElainTarha
{
protected:
&nbsp;&nbsp;&nbsp; CElain\* Elaimet\[100\];
&nbsp;&nbsp;&nbsp; int ElainLaskuri;

public:
&nbsp;&nbsp;&nbsp; CElainTarha() : ElainLaskuri(0)
&nbsp;&nbsp;&nbsp; {
&nbsp;&nbsp;&nbsp; }
{     }\\

&nbsp;&nbsp;&nbsp; \~CElainTarha()
&nbsp;&nbsp;&nbsp; {
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; for (int i=0; i<ElainLaskuri; i++) {
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
{             delete Elaimet\[i\];
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;         }
&nbsp;&nbsp;&nbsp; }
\\

&nbsp;&nbsp;&nbsp; bool LisaaElain(CElain\* Elain) {
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if (ElainLaskuri < 100) {
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
{             Elaimet\[ElainLaskuri\] = Elain;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp; &nbsp;&nbsp;             ElainLaskuri++;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;             return true;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; } else {
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;         }
else
{             return false;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;         }
&nbsp;&nbsp;&nbsp; }
\\

&nbsp;&nbsp;&nbsp; void SyotaElaimet() {
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; for (int i=0; i<ElainLaskuri; i++) {
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
{             Elaimet\[i\]->Syo();
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;         }
&nbsp;&nbsp;&nbsp; }
};
\\

int main()
{
&nbsp;&nbsp;&nbsp; CElainTarha ElainTarha;

&nbsp;&nbsp;&nbsp; ElainTarha.LisaaElain(new CKissa);
&nbsp;&nbsp;&nbsp; ElainTarha.LisaaElain(new CKoira);
&nbsp;&nbsp;&nbsp; ElainTarha.LisaaElain(new CKissa);
&nbsp;&nbsp;&nbsp; ElainTarha.LisaaElain(new CKoira);
&nbsp;&nbsp;&nbsp; ElainTarha.LisaaElain(new CKissa);

&nbsp;&nbsp;&nbsp; ElainTarha.SyotaElaimet();
}
Esimerkki tulostaa seuraavat rivit:

Kissa syo kalaa...
Koira syo lihaa...
Kissa syo kalaa...
Koira syo lihaa...
Kissa syo kalaa...
Esimerkissä luodaan kantaluokka, CElain ja siitä periytetään kaksi  perillistä, CKissa ja CKoira. Lisäksi luodaan CElainTarha-luokka, johon  voidaan tuoda CElain-tyyppisiä&nbsp;osoittimia olioihin,   riippumatta siitä, onko ne luotu CKissa vai CKoira \-luokista. Tämä  onnistuu siksi, että molemmilla luokilla on sama kantaluokka, CElain.  Kutsumme lopuksi CElainTarhan metodia SyotaElaimet(), joka 'syöttää'  jokaista eläintä, eli kutsuu sekä kissojen että koirien  Syo()-metodeita.

Etuna tässä toteutustavassa on, että jatkossa voidaan luoda uusi  CElain-luokan perillinen, esim. CKirahvi. Tästä luokasta tehty olio  voidaan viedä CElainTarha-luokkaan,&nbsp;  ilman että sen koodia tarvitsee muuttaa ollenkaan.