...
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 funktioista halutaan käyttää:
Code Block |
---|
int main() |
...
{ CPegasus pegasus; pegasus.CLintu::Syo(); |
...
} |
Moniperintä ohjelmointikielissä
Kaikki olio-ohjelmointikielet eivät tue moniperintää, kuten esim Java. Moniperintä on kuitenkin 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:
virtual ~CElain() {} // Toteutus tulee olla (tyhjäkin käy).
virtual void Syo() = 0; // Aito virtuaalifunktio .
};
// CElain-kantaluokan toteuttava luokka.
class CKissa : public CElain
{ public:
void Syo() { cout << "Kissa syo kalaa...\n"; }
};
// CElain-kantaluokan toteuttava luokka.
class CKoira : public CElain
{ public:
void Syo() { cout << "Koira syo lihaa...\n"; }
};
// Luokka johon voidaan tuoda CElain-luokan perillisiä.
class CElainTarha
Wiki Markup |
---|
\{ protected:
CElain\* Elaimet\[100\];
int ElainLaskuri;
public:
CElainTarha() :
ElainLaskuri(0) \{ \}\\ |
...
Wiki Markup |
---|
bool LisaaElain(CElain\* Elain)
\{ if (ElainLaskuri < 100) \{ Elaimet\[ElainLaskuri\] = Elain; ElainLaskuri++; return true; \}
else
\\
\{ return false; \}
\}
\\ |
...
int main()
{
CElainTarha ElainTarha;
ElainTarha.LisaaElain(new CKissa);
ElainTarha.LisaaElain(new CKoira);
ElainTarha.LisaaElain(new CKissa);
ElainTarha.LisaaElain(new CKoira);
ElainTarha.LisaaElain(new CKissa);
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ä 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, ilman että sen koodia tarvitsee muuttaa ollenkaan.