// elukat.cpp // Malliohjelma perimisesta ja polymorfismista (monimuotoisuudesta) // Vesa Lappalainen 12.2.1999 // Miika Nurminen 24.10.2007 #include #include #include #include using namespace std; //--------------------------------------------------------------------------- // cElain //--------------------------------------------------------------------------- class cElain { string nimi; double paino; int ika; public: cElain(); cElain(const string &inimi); virtual ~cElain(); void kasva(double dm); void tulosta() const; void vanhene(int v=1); // virtual void aantele() const=0; virtual void aantele() const; string& annaNimi() { return nimi; } }; cElain::cElain() { cout << "cElain (oletuskonstruktori) " << nimi << "(" << typeid(this).name() << ")" << endl; } cElain::cElain(const string &inimi) { nimi = inimi; ika = 0; paino = 0.1; // typeid palauttaa luokan nimen - merkkijonon tarkka muoto vaihtelee eri kääntäjillä cout << "cElain " << inimi << "(" << typeid(this).name() << ")" << endl; this->aantele(); // ei suositeltavaa! - tässä vaiheessa olio on cElain, // jolloin kutsutaan cElaimen aantele-metodia, vaikka oltaisiin luomassa muuta! } // Jos luokkaa on mahdollista periä, pitää hajottaja esitellä virtuaaliseksi. cElain::~cElain() { cout << "~cElain " << nimi << "(" << typeid(this).name() << ")" << endl; this->aantele(); // kääntäen sama tilanne oliota tuhottaessa } void cElain::kasva(double dm) // scope resolution operator :: { paino += dm; if ( paino < 0.1 ) paino = 0.1; } void cElain::tulosta() const { cout << "Elain: " << nimi << " " << paino << " " << ika << "\n"; } void cElain::vanhene(int v) { if ( v < 0 ) return; ika += v; } void cElain::aantele() const { cout << "???" << endl; } //--------------------------------------------------------------------------- // cKissa //--------------------------------------------------------------------------- class cKissa : public cElain { public: cKissa(const string &inimi) : cElain(inimi) {} virtual void aantele() const { cout << "Miuaa"; } }; //--------------------------------------------------------------------------- // cKoira //--------------------------------------------------------------------------- class cKoira : public cElain { public: double hannanpituus; cKoira(const string &inimi, const double ihannanpituus=0.5) : cElain(inimi),hannanpituus(ihannanpituus) { cout << "cKoira " << inimi << "(" << typeid(this).name() << ")" << endl; aantele(); } ~cKoira() { cout << "~cKoira " << annaNimi() << "(" << typeid(this).name() << ")" << endl; aantele(); } virtual void aantele() const { // esimerkki yliluokan metodin kutsusta //cElain::aantele(); cout << "Hauhau"; } // kuormitettu virtuaalifunktio "peittää" alkuperäisen, // ellei myös alkuperäistä syrjäytetä virtual void aantele(string aani) const { cout << aani; } }; //--------------------------------------------------------------------------- // Polymorfismia esitteleviä aliohjelmia //--------------------------------------------------------------------------- // Esimerkki polymorfismista referenssin kanssa void aantele(const cElain &elain) { elain.aantele(); } // Esimerkki polymorfismista osoittimen kanssa void kasvata(cElain *elain, double dm) { elain->kasva(dm); elain->tulosta(); } // Esimerkki polymorfismismin toimimattomuudesta arvojen kanssa // eli vain osoittimet ja referenssit voivat olla polymorfisia // abstraktia luokkaa ei voi antaa konkreettisena parametrina /* void vanhenna(cElain elain) { elain.vanhene(); elain.aantele(); elain.tulosta(); } */ void vanhenna(cElain* elain) { elain->vanhene(); elain->aantele(); elain->tulosta(); } //--------------------------------------------------------------------------- int main(void) { cKissa mirri("Miuku"); cKissa kolli("Molli"); cKoira musti("Musti"); cElain* ressu = new cKoira("Ressu",0.4); ressu->tulosta(); delete ressu; // jos destruktori ei ole virtuaalinen, cKotkan destruktori jäisi kutsumatta! mirri.tulosta(); musti.tulosta(); kolli.tulosta(); mirri.kasva(1.2); mirri.tulosta(); kolli.kasva(-0.5); kolli.tulosta(); mirri.vanhene(); mirri.tulosta(); mirri.vanhene(-3); mirri.tulosta(); mirri.tulosta(); mirri.aantele(); kolli.aantele(); musti.aantele(); // Polymorfismitesti referenssin ja osoittimen kanssa cout << "\n---------------------------------------------------\n"; aantele(mirri); aantele(kolli); aantele(musti); cout << "\n"; kasvata(&mirri,1); kasvata(&kolli,2); kasvata(&musti,0.5); // vanhenna(mirri); // Arvoilla polymorfismi ei toimi! vanhenna(&mirri); mirri.tulosta(); vector elaintarha; elaintarha.push_back(&musti); elaintarha.push_back(&mirri); elaintarha.push_back(&kolli); // polymorfinen vektori (huom! täytyy käyttää osoittimia // tai viitteitä! vektorin sijasta voitaisiin yhtä hyvin // käyttää taulukkoa, hajautustaulua (map) jne. vector::iterator vi = elaintarha.begin(); while (vi != elaintarha.end()) { (*vi)->tulosta(); (*vi)->aantele(); vi++; // kasvatetaan iteraattoria cout << endl; } return 0; }