Moniperiytyminen

Periytymisen teoriatasolla voi luokka periytyä useammasta kuin yhdestä luokasta. Moniperiytymisellä (engl. multiple inheritance) tarkoitetaan tällaisia tilanteista, joissa luokka periytetään kahdesta tai useammasta kantaluokasta. Koska moniperiytyminen on käytännössä varsin mutkikas mekanismi, hyvä lähtökohta koko asiaan on pyrkiä välttämään moniperiytymistä. Samalla sille on muutama hyvin selkeä, järkevä, käyttökohde.

Moniperiytymisessä luokka siis perii kantaluokkiensa ominaisuudet eli moniperiytyminen on periytymistä. Aliluokan olio koostuukin nyt kantaluokkiensa olioista sekä aliluokan omasta näiden toiminnallisuutta laajentavasta osasta. Polymorfismi pätee myös moniperiytymisessä: aliluokan olio kelpaa minkä tahansa kantaluokkansa olioksi. On siis erittäin tärkeä moniperiytymisestä puhuttaessa muistaa perussääntö: aliluokan olio on aina (jokaisen) kantaluokkansa olio. Jos is-a-suhdetta ei kaikkien kantaluokkien kanssa ole, moniperiytymisen sijaan oikea ratkaisu on esimerkiksi kooste eli valmiiden luokkien asettaminen jäsenmuuttujiksi. Tarvittaessa jäsenmuuttujien jäsenfunktioita voidaan koosteessakin kutsua ns. läpikutsufunktion (engl. call-through function), joka vain kutsuu jäsenmuuttujan jäsenfunktiota, avulla.

Moniperiytymisen käyttö

Selkein paikka moniperiytymisen käytölle on rajapintaluokkien tarjoamien rajapintojen toteuttaminen. Luokkaan voidaan moniperiyttämällä rajapintaluokkia yhdistää useampi rajapinta ja toteuttaa ne aliluokassa. Toinen käyttökohde moniperiytymiselle on kahden tai useamman olemassaolevan luokan yhdistäminen luokaksi, joka laajentaa tai täydentää useampaa valmista luokkaa. Tyypillisin käyttökohde tällaiselle on valmiit oliokirjastot ja sovelluskehykset, joissa on tarjolla luokkia, jotka on suunniteltu toimimaan juuri tällaisessa käyttötarkoituksessa. Riskinä kuitenkin on, että kantaluokat häiritsevät toistensa toimintaa. Tällainen tilanne voi syntyä esimerkiksi, jos molemmista kantaluokista periytyy samanlainen jäsenfunktio. Toinen mahdollinen ongelma on toistuva moniperiytyminen, jossa sama kantaluokka periytyy aliluokalle epäsuorasta useammin kuin kerran. Vaikka tämä joskus saattaakin olla toivottavaa, liittyy tilanteeseen niin monta mutkaa matkaan, että tässä kohtaa kannattaa vain välttää toistuvaa moniperiytymistä kokonaan.

Moniperiytymistä ei pidä käyttää, jos aliluokalla ei ole selkeää is-a-periytymissuhdetta molempiin kantaluokkiinsa. Sitä ei siis voi käyttää siten, että aliluokka olisi osan aikaa toinen kantaluokistaa ja osan aikaa toinen: se on aina molempia. Moniperiytyminen ei myöskään ole tapa saada joltain luokalta jokin toiminnallisuus osaksi aliluokkaa, koska perittäviltä kantaluokilta peritään aina koko julkinen rajapinta. Moniperiytyminen myös lisää ohjelman rakenteen monimutkaisuutta, joten sen käytössä pitää käyttää harkintaa. Usein esim. jäsenmuuttuja on oikea ratkaisu.

Moniperiytyminen Javassa ja C++:ssa

Java ja C++ muodostavat moniperiytymisen suhteen mielenkiintoisen kieliparin: Javassa moniperiytymistä ei ole luokkatasolla ollenkaan vaan jokaisella luokalla voi olla tasan yksi kantaluokka. Java ei tästä huolimatta kuitenkaan täysin kiellä moniperiytymistä. Se rajoitetaan rajapintojen (ìnterface) toteuttamiseen eli Java sallii rajapintaluokkien moniperiyttämisen.

C++ puolestaan jättää kaiken ohjelmoijan vastuulle: moniperiytymistä saa käyttää. Tämä antaa ohjelmoijalle mahtavia mahdollisuuksia, mutta sälyttää myös kaikki sudenkuopat ohjelmoijan vältettäviksi. Moniperiytyminen on C++:ssa myös käytössä täysin luokkatasolla rajapintaluokkien kohdalla. C++:ssa ei ole syntaktisesti erilaista rajapintaluokkaa niinkuin Javassa vaan rajapintaluokka on vain luokka, jonka kaikki jäsenfunktiot ovat virtuaalisia eikä niille ole annettu kantaluokassa toteutusta.