Öröklődés (objektumorientált programozás)

fogalom az objektumorientált programozás köréből

Objektumorientált programozásnál az öröklődés (angolul inheritance) mechanizmusa, hogy egy objektumot vagy egy osztályt alapjául választunk egy másik objektumnak (prototípus-alapú öröklődés) vagy osztálynak (osztályalapú öröklődés), megtartva a hasonló implementációt. Más néven egy új osztályt (alosztályt) származtatunk egy már létező szuper- vagy alaposztályból, amiket aztán osztályok hierarchiájává formázunk. A legtöbb osztály-alapú objektum-orientált nyelvben egy öröklődésen keresztül létrehozott objektum a „gyermekobjektum” megkapja az ő „szülőobjektumának” minden tulajdonságát és viselkedését, leszámítva a konstruktorokat, destruktorokat, túlterhelt operátorait és barát függvényeit. Az öröklődés lehetővé teszi, hogy már létező osztályokra hozzunk létre újakat,[1] ezzel annak egy új implementációját megalkotva úgy, hogy közben a viselkedését megtartja (interfész implementálása). Ez hasznos, mivel újrahasznosításra kerül a kód, emellett publikus osztályok és interfészek segítségével szabadon bővíthető marad az eredeti szoftver. Objektumok vagy osztályok közötti öröklődés által kialakult kapcsolatok jól szemléltethetők irányított gráfokkal.

Az öröklődést 1969-ben találták fel a Simula[2] nyelvhez, de azóta már számos egyéb objektum-orientált nyelv is átvette, például a Java, a C++ vagy a Python.

Egy öröklő osztály az alosztálya az ő szuperosztályának. Rokonsági metaforákkal szülőosztályról és gyermekosztályokról vagy ősosztályról és leszármazott osztályokról is beszélhetünk. Az „öröklődés” kifejezést ritkábban szoktuk használni mind az osztály-alapú, mint a prototípus-alapú programozás esetében, azonban szigorúbban véve a kifejezés az osztályalapú programozás szótárának része (egyik osztály örököl a másiktól). Ennek megfelelője a prototípus-alapú programozásban a delegáció (egyik osztály a másikhoz delegálódik).

Az öröklődés nem összetévesztendő az altípusokkal.[3][4] Bizonyos nyelvek esetén az öröklődés és altípusok megegyeznek, mások esetén nem; általánosságban elmondható, hogy az altípusok is-a kapcsolatban állnak, míg az öröklődés csak újrahasznosítja az implementációt és inkább szintaktikai kapcsolatot hoz létre, nem szükségszerűen szemantikait (az öröklődés nem feltétlen vonja magával a viselkedési altípusokat). Hogy különbséget tehessünk ezen fogalmak közt, az altípusokat interfészöröklődésnek is szoktuk nevezni, míg az öröklődés, a jelen írt definíció szerint is implementációöröklődés vagy kód öröklődés.[5] Ugyanakkor az öröklődés egy gyakran használt módja altípus kapcsolatok létrehozásának.[6]

Az öröklődést az objektum-összetétellel szokás szembe állítani, ahol egy objektum tartalmazza a másik objektumot (vagy egy osztályból származó objektum tartalmazza egy másik osztály objektumait); lásd: Öröklődés helyett objektum-összetétel. A kompozíció has-a kapcsolatot implementál, szemben az altípusok is-a kapcsolatával.

Típusok szerkesztés

 
Egyszeres öröklődés
 
Többszörös öröklődés

Az öröklődésnek számos típusa létezik, melyeket minták és konkrét nyelvek határoznak meg.[7][8]

Egyszeres öröklődés

ahol az alosztályok megörökölik egy szuperosztály tulajdonságait. Egy osztály szert tesz egy másik osztály funkcióira.

Többszörös öröklődés

mikor egy osztály rendelkezhet egynél több szuperosztállyal és az összes szülőosztály tulajdonságait megörököli.

„Többszörös öröklődés hatékony implementálása széles körben nagy kihívásnak számított. Például Brad Cox az Objective-C-ről szóló könyvében egy, a C++ -t summázó fejezetben úgy vallotta, hogy a többszörös öröklődés implementálása a C++ nyelvbe lehetetlen volt. Ezért a többszörös öröklődés nagy kihívásnak tűnt. Mivel nekem már 1982-ben megfordult a fejemben a többszörös öröklődés fogalma és 1984-ben találtam egy egyszerű és hatékony technikát implementálására, nem tudtam ellenállni a kihívásnak. Gyanítom, hogy ez az egyetlen olyan eset, ahol a divat módosította az események menetét.[9]

Bjarne Stroustrup

Többszintű öröklődés

mikor egy alosztály egy másik alosztály leszármazottja. Nem ritka, hogy egy osztály egy származtatott osztályból származik, ahogy ezt a „Többszintű öröklődés” ábra is bemutatja.

 
Többszintű öröklődés

Az A osztály alaposztályként szolgál a származtatott B osztálynak, mely továbbá alaposztályként szolgál az abból származtatott C osztálynak. A B osztályt szokás közbülső alaposztálynak is nevezni, mert egyfajta összeköttetést biztosít az A és C közötti öröklődésben. Az ABC láncot öröklődési láncnak hívják.

Többszintű öröklődés során osztályszármaztatásnak deklarációja:

Class A(...);      // Alaposztály
Class B : public A(...);   // B származik az A-ból
Class C : public B(...);   // C származik a B-ből

Ezt a folyamatot a végtelenségig lehet végezni.

Hierarchikus öröklődés

Ebben az esetben egy osztály több alosztály számára szolgál alaposztályként. Például egy A szülőosztály rendelkezhet kettő alosztállyal, B-vel és C-vel. B-nek és C-nek is A az ősosztálya, de B és C két egymástól különálló alosztály.

Hibrid öröklődés

Erről akkor beszélhetünk, mikor kettő-, vagy többfajta öröklődés egyszerre áll fenn a fentiek közül. Például az A osztály rendelkezik egy B alosztállyal, melynek van két alosztálya, C és D. Ez a többszintű öröklődés és a hierarchikus öröklődés keveréke.

Alosztályok és szuperosztályok szerkesztés

Alosztályok, származtatott osztályok, örökösosztályok, vagy gyermekosztályok valójában mind moduláris származtatott osztályok melyek egy, vagy több nyelvi elemet örökölnek egy vagy több egyéb osztályokból (szuperosztály, alaposztály, szülő- vagy ősosztály). Az osztályöröklődés szemantikája nyelvenként eltérő lehet, de az alosztály általában automatikusan örököli a szuperosztály példányszintű változóit és tagfüggvényeit.

Származtatott osztály létrehozásának általános bemutatása:[10]

class Aloszály: láthatóság Ősosztály
{
    // alosztály tagok
};
  • A kettőspont reprezentálja, hogy az alosztály örököl a szuperosztálytól. A visibility (láthatóság) opcionális, private vagy public értékeket vehet fel. Az alapértelmezett láthatóság a private. A láthatóság határozza meg hogy az ősosztály metódusai és mezői publikusan-, vagy privát módon származódnak.

Néhány nyelv más szerkezetek öröklését is támogatják. Az Eiffel-ben például a contract-okat, melyek specifikációval látják el az osztályokat, az utódok szintén képesek örökölni. Az ősosztály létrehoz egy közös interfészt és egy alapvető függőséget, melyet speciális alosztályok képesek örökölni, módosítani és bővíteni. Egy alosztály által örökölt szoftver az alosztály szempontjából újrahasznosítottnak minősül. Egy osztály példányára mutató referencia lehet, hogy valójában annak egy alosztályára mutat. A mutatott objektum valódi osztályát lehetetlen meghatározni fordításidőben. Számos különböző osztály tagfüggvényeinek objektumai egy egységes interfészen keresztül kerülnek meghívásra. Az alosztályok akár teljesen felülírhatják az ősosztály függvényeit amennyiben megegyezik a metódus szignatúra.

Nem-alosztályosítható osztályok szerkesztés

Egyes nyelvek esetén az osztályok definiálhatók nem-alosztályosítható osztályként bizonyos osztálymódosító kulcsszavak segítségével. Ilyenek például a final kulcsszó Java és C++11 és újabb verziójában, vagy a sealed C#-ban. Ezen kulcsszavak az osztálydeklaráció során kerülnek feltüntetésre a class szó előtt. Az ilyen nem-alosztályosítható osztályok korlátozzák az újrahasznosíthatóságot, kiváltképp mikor a fejlesztők a forráskódhoz nem férnek hozzá, csak az előrefordított binárisához.

Egy nem-alosztályosítható osztálynak nincsenek alosztályai, ezért már fordítási időben is egyértelmű, hogy az ennek az osztálynak objektumaira mutató referenciák, vagy pointerek valóban ennek az osztálynak példányaira mutatnak, nem pedig alosztályainak példányaira (nincsenek) vagy szuperosztályainak példányaira (egy referenciatípus felfelé kasztolása sérti a típusrendszert). Mivel a mutatott objektum pontos típusa már a futtatás előtt ismert, használható korai kötés (static dispatch) késői kötés (dynamic dispatch) helyett, melyhez szükség van legalább egy virtuális metódustábla keresésre annak függvényében, hogy a használt programozási nyelv támogatja-e a többszörös örököltetést, vagy csak az egyszeres örököltetést.

Nem-felülírható metódusok szerkesztés

Ahogy egy osztály lehet nem-alosztályosítható, úgy a metódus deklarációk is tartalmazhatnak olyan kulcsszavakat, melyek megakadályozzák, hogy felülírásra kerüljön az (vagyis, hogy egy alosztályban kicseréljék azt egy új metódusra, mellyel a neve és szignatúrája megegyezik). Egy privát metódus nem írható felül egyszerűen azért, mert a saját osztályán kívül senki más nem fér hozzá (habár ez a C++-ra nem igaz). Java-ban egy final metódus, C#-ban egy sealed metódus vagy Eiffel-ben egy frozen metódus nem felülírható.

Virtuális metódusok szerkesztés

Hogyha a szuperosztály metódusa virtuális, a metódus-hozzárendelés dinamikusan történik. Egyes nyelvek megkívánják, hogy ezeket a metódusokat expliciten virtuálisként hozzuk létre (pl.: C++), míg másokban minden metódus alapból virtuális (pl.: Java). Egy nem-virtuális metódushíváshoz történő metódus-hozzárendelés mindig statikus módon kerül lekötésre (a függvényhívás címe fordításidőben dől el). A statikus átadás gyorsabb, mint a dinamikus.

Örökölt tagok láthatósága szerkesztés

Source:[11]

Alaposztály láthatóság Származó osztály láthatóság
Public származtatás Private származtatás Protected származtatás
  • Private →
  • Protected →
  • Public →
  • Nem örökölt
  • Protected
  • Public
  • Nem örökölt
  • Private
  • Private
  • Nem örökölt
  • Protected
  • Protected

Alkalmazása szerkesztés

Örököltetéssel képesek vagyunk összekapcsolni egy, vagy több osztályt egymással.

Felülírás szerkesztés

 
Metódus felülírás illusztrációja

Számos objektum-orientált programozási nyelv lehetővé teszi osztályainak vagy objektumainak, hogy kicseréljék egy általa örökölt aspektus implementációját (általában egy viselkedés). Ez a folyamat a felülírás. A felülírás egy problémát szül: a viselkedés melyik verzióját használja az örökölő osztály példánya – azt, amelyik az ő saját osztályának része, vagy amelyik az ő szülőosztályából származik? A válasz nyelvenként különbözik, emellett néhány osztály lehetőséget biztosít arra, hogy jelezzük az adott viselkedésnek, hogy azt nem lehet felülírni, úgy kell viselkednie, ahogy azt az alaposztály definiálta. Például C#-ban az alap metódus, vagy property csak akkor felülírható egy alosztályban, ha ellátták őket virtual, abstract vagy override kulcsszavak valamelyikével, míg például a Java esetében különböző metódusok hívhatók meg, hogy felülírjanak metódusokat.[12] Felülírás alternatívája az örökölt kód elrejtése.

Kódújrahasznosítás szerkesztés

Az implementációöröklődés egy olyan folyamat, ahol az alosztály az alaposztály kódját felhasználja. Alapértelmezés szerint az alosztály megtartja az ősének összes funkcióját, de az alosztály felülírhatja akár az összes metódusát kicserélve ezzel az alaposztály implementációját az ő sajátjára.

Az alábbi Python példában a SquareSumComputer és a CubeSumComputer alosztályok fölülírják a SumComputer alaposztály transform() metódusát. Az alaposztály tartalmaz műveleteket, mely kiszámolja két szám négyzetének összegét. Az alosztály újrahasznosítja az alaposztály összes funkcionalitását, kivéve azt, mely a szám négyzetét számolja ki. Helyette felülírja egy olyan metódussal, mely vagy a négyzetét vagy a köbét számolja ki az adott számnak. Ennek megfelelően az alosztályok a számok négyzetének/köbének összegét számolják ki.

Alább látható a példa Pythonban.

class SumComputer(object):
    def __init__(self, a, b):
        self.a = a
        self.b = b

    def transform(self, x):
        raise NotImplementedError

    def inputs(self):
        return range(self.a, self.b)

    def compute(self):
        return sum(self.transform(value) for value in self.inputs())

class SquareSumComputer(SumComputer):
    def transform(self, x):
        return x * x

class CubeSumComputer(SumComputer):
    def transform(self, x):
        return x * x * x

A világ nagyrészén pusztán a kódújrahasznosításért használt osztályöröklés már divatjátmúlt.[forrás?] Ennek legfőbb oka az, hogy az implementációöröklés nem biztosítja a polimorfikus helyettesíthetőséget – egy újrahasznosító osztály példánya nem feltétlen helyettesíthető az örökölt osztály példányával. Egy alternatíva erre az explicit delegáció, több programozási erőbefektetésre van szükség, de elhárítja a kicserélhetőség problémáját.[forrás?] C++ -ban a private öröklődés használható az implementációöröklődés egy formájaként kicserélhetőség nélkül. Miközben a public öröklődés egy "is-a" kapcsolatot reprezentál, a delegáció pedig "has-a"-t, a private (és protected) öröklődésre gondolhatunk "A implementálva B szerint" kapcsolatként.[13]

Egy másik gyakori használati felülete az öröklődésnek, hogy garantáljuk, hogy az osztályaink rendelkeznek bizonyos közös pontokkal; magyarul, ugyan azokat a metódusokat implementálják. Az ősosztály állhat már implementált műveletek halmazából, valamint műveletekből, melyek implementálását a gyermekosztályainak kell elvégezni. Leggyakrabban nem változik az interfész, az alap és az alosztály között – a gyermek implementálja a leírt viselkedést az őse helyett.[14]

Öröklődés vagy altípusok szerkesztés

Az öröklődés hasonlít az altípusokhoz, de valójában két külön dolog.[15] Altípusok lehetővé teszik, hogy egy adott típust egy másik típussal vagy absztrakcióval helyettesítsük, ezzel is-a kapcsolatot létrehozva az altípus és egy már létező absztrakció között. Ez történhet expliciten vagy impliciten, a használt nyelvtől függ. A kapcsolatot expliciten is ki lehet fejezni öröklődéssel olyan nyelvek esetén, melyek támogatják, hogy az öröklődést altípusként használjuk. Példaként, az alábbi C++ kód A és B osztály között expliciten állít fel egy öröklődési kapcsolatot, ahol B egyszerre alosztálya és altípusa A-nak és használható A-ként akárhányszor egy B-t hozunk létre (magára az objektumra mutató referenciával, pointerrel).

class A {
 public:
  void DoSomethingALike() const {}
};

class B : public A {
 public:
  void DoSomethingBLike() const {}
};

void UseAnA(const A& a) {
  a.DoSomethingALike();
}

void SomeFunc() {
  B b;
  UseAnA(b);  // B használható A-ként is.
}

Olyan programozási nyelvek esetén, melyek nem támogatják az öröklődés altípusként történő használatát, az alaposztály és a származtatott osztály közötti kapcsolat mindössze implementációk közötti kapcsolat (mely a kódújrahasznosítást segíti elő), nem pedig típusok közötti kapcsolat. Az öröklődés, még olyan nyelvek esetén is, melyek támogatják az öröklődés altípusként történő használatát nem feltétlen vonja maga után a viselkedési altípusokat. Teljességgel lehetséges úgy származtatni egy osztályt, hogy annak egy objektuma helytelenül fog egy olyan kontextusban viselkedni, ahol az ő ősének viselkedése az elvárt; lásd: Liskov helyettesítési elv.[16] Egyes OOP nyelveknél a kódújrahasznosítás és az altípusok fogalma egybeesik, mert egy altípus létrehozásának egyetlen módja, hogy létrehozzunk egy új osztályt, ami megörököli egy másiknak implementációját.

Tervezési megszorítások szerkesztés

Egy program tervezésekor az öröklődés túlzott használata magával von némi megszorítást. Például, vegyünk egy Személy osztályt, mely tartalmazza a személy nevét, születési dátumát, címét és telefonszámát. Létrehozhatunk ennek egy Diák alosztályát, mely tartalmazza a személy tanulmányi átlagát és felvett tárgyait. A Személy osztály egy másik alosztálya, az Alkalmazott, mely tartalmazza az ő munkájának megnevezését, alkalmazóját és fizetését. Azáltal, hogy létrehoztuk ezt az öröklődési hierarchiát, már definiáltunk is néhány megszorítást, melyek nem feltétlen kívánatosak:

Egyszeriség

Egyszeri öröklődés használatával az alosztály csak egyetlen szuperosztálytól képes örökölni. A fenti példát követve egy Személy vagy csak Diák lehet, vagy csak Alkalmazott, a kettő egyszerre nem. Többszörös öröklődés részlegesen megoldja ezt a problémát, vele létrehozhatunk egy DiákAlkalmazott osztályt, mely a Diákból és az Alkalmazott-ból is örököl. Azonban a legtöbb implementáció esetén minden szuperosztályból még mindig csak egyszer örökölhet, ezért nem támogatja azokat az eseteket, mikor egy diák két munkahelyen dolgozik és két intézményben tanul egyszerre. Az Eiffel-ben elérhető öröklődési modell lehetővé teszi ezt az un. ismételt öröklődés támogatásával.

Statikus

Egy objektum öröklődési hierarchiája példányosításkor lefixálódik, mikor annak típusa kiválasztásra kerül, és idővel nem változik. Például az öröklődési gráf nem engedi, hogy egy Diák objektum Alkalmazott objektummá váljon úgy, hogy megtartsa a Személy szuperosztályának állapotát. (Az e fajta viselkedés megvalósítható a díszítő tervezési minta használatával). Néhányan kifogásolják az öröklődést, azt állítják, hogy röghöz köti a fejlesztőket az eredeti tervezési normákhoz.[17]

Láthatóság

Akárhányszor egy kliens kódrészlet hozzáfér egy objektumhoz, hozzáfér annak az objektumnak az összes szuperosztályának adataihoz. Még ha a szuperosztály nem is publikus, attól a kliens ugyanúgy képes a szuperosztályának típusára kasztolni az objektumot. Például lehetetlen lenne egy függvénynek egy mutatót adni egy Diák tanulmányi átlagára majd lemásolni azt anélkül, hogy ennek a függvénynek hozzáférést adnánk a diák összes személyes adatihoz, melyek az ő szuperosztályában, a Személy-ben vannak tárolva. Számos modernebb nyelv, beleértve a C++ -t és Java-t biztosít egy „protected” hozzáférési szintet mely lehetővé teszi az alosztályok számára, hogy hozzáférjenek az adatokhoz anélkül, hogy olyan kód is hozzáférne, mely nem része az öröklési láncnak.

Az Öröklődés helyett objektum-összetétel elv egy jó alternatíva az öröklődésre. E technika oly módon támogatja a polimorfizmust és a kódújrahasznosítást, hogy szétválasztja a viselkedéseket a fő osztályhierarchiától, és speciális viselkedési osztályokat vezet be, ahogy azt megkövetei bármely business domain osztály. Ez a megközelítés kikerüli az öröklődési hierarchia statikus természetét úgy, hogy lehetőséget ad futás közbeni viselkedésmódosításokra. Lehetővé tesz egy osztály számára, hogy szabadon implementálhasson egy viselkedést, nincs lekorlátozva az ősosztályainak viselkedéseire.

Problémák és alternatívák szerkesztés

Az implementációs öröklődés legalább a ’90-es évek óta egy igen megosztó téma a programozók és elméleti szakemberek köreiben. Köztük vannak a Design Patterns szerzői is, akik párolják az interfészöröklődést, és előnyben részesítik a kompozíciót az öröklődés fölött. Például a (korábban már említett) díszítő mintát ajánlják az öröklődés osztályok közötti statikus természetének kiküszöbölésére. Egy inkább alapvető megoldás a problémára a szerep-orientált programozás által biztosított különálló kapcsolati forma, az "által játszott", mely egy új koncepcióvá gyúrja össze az öröklődés és a kompozíció tulajdonságait.[forrás?]

Allen Holub szerint az implementációöröklődés legfőbb problémája, hogy fölösleges párosításokat hoz létre a "törékeny alaposztály probléma":[5] formájában: az alaposztály implementációjában történő módosítások az alosztályokban nem várt viselkedési változást eredményeznek. Interfészek használatával kiküszöbölhető ez a probléma, mivel az API-n kívül nincs közös implementáció.[17] Ennek kifejezésére egy másik mód, hogy az „öröklődés sérti az egységbezárást”.[18] A probléma tisztán megmutatkozik objektum-orientált rendszerekben, mint a keretrendszerekben, ahol a klienskódtól azt várjuk, hogy örököljön a rendszer által biztosított osztályokból, majd helyettesítve ezzel a rendszer osztályit algoritmusaiban.[5]

Állítólag a Java feltalálója, James Gosling az implementációöröklődés ellen szólt, azt állította, hogy ha újratervezné a Java nyelvet, nem tenné bele azt.[17] Olyan nyelvek, melyek szétválasztják az öröklődést az altípusoktól (interfészöröklődés) már 1990-ben megjelentek;[19] ennek egy modern példája a Go programozási nyelv.

Összetett öröklődés, vagy egy nem eléggé fejlett környezetben használt öröklődés a jojó problémához vezethet. A ’90-es évek vége felé, mikor még az öröklődés volt egy rendszer kódstruktúrájának felépítésének elsődleges eszköze, a fejlesztők, ahogy nőtt a rendszer funkcionalitása, értelemszerűen széttördelték a kódot az öröklődés rétegjei szerint. Mikor a fejlesztőcsapat több réteg öröklődést fűzött össze egyetlen felelősségi elvvel, az a kódnak számos szupervékony rétegét hozta létre, melyek közül soknak rétegenként csak 1-2 sor kódja volt. Mielőtt a csapatok megtanulták volna, hogy a 2-3 réteg az optimális mennyiség, mely képes egyensúlyt tartani a kódújrahasznosítás előnyei, és a rétegenként növekvő komplexitás hátrányai közt, nem volt ritka, hogy 10, de akár 30 rétegből álló öröklődési keretrendszerrel dolgoztak. Példának okáért a 30 rétegen történő hibaelhárítás komoly kihívást jelentett, mivel nehéz volt megtalálni, hogy melyik réteget kell debugolni. PowerBuilder készítette az egyik legjobb kódkönyvtárat, mely elsősorban az öröklődést használta, de mindössze csak 3-4 rétegszámmal. Egy öröklődésikönyvtárban létfontosságú, hogy a rétegek száma ne haladja meg a 4-et, különben a könyvtár túlságosan összetetté, használata pedig időigényessé válik.

Az öröklődés egy másik hibája, hogy az alosztályokat a kódban kell definiálni, mely azt eredményezi, hogy a programhasználók nem adhatnak hozzá új alosztályokat. Más tervezési minták, (mint az Entitás-komponens-rendszer) lehetővé teszi, hogy a programhasználók futási időben definiáljanak entitások variánsait.

További linkek szerkesztés

Jegyzetek szerkesztés

  1. Johnson, Ralph: Designing Reusable Classes. www.cse.msu.edu , 1991. augusztus 26.
  2. Mike Mintz, Robert Ekendahl. Hardware Verification with C++: A Practitioner's Handbook. United States of America: Springer, 22. o. (2006). ISBN 978-0-387-25543-9 
  3. (1990) „Inheritance is not subtyping”. Proc. 17th ACM SIGPLAN-SIGACT Symp. on Principles of Programming Languages (POPL): 125–135. doi:10.1145/96709.96721. 
  4. Cardelli, Luca (1993). „Typeful Programming”, 32–33. o.  
  5. a b c (1998) „A study of the fragile base class problem”. Proc. 12th European Conf. on Object-Oriented Programming (ECOOP) 1445: 355–382. [2017. augusztus 13-i dátummal az eredetiből archiválva]. doi:10.1007/BFb0054099. Hozzáférés: 2020. június 15. 
  6. (2013) „What programmers do with inheritance in Java”. ECOOP 2013–Object-Oriented Programming: 577–601. 
  7. C++ Inheritance. www.cs.nmsu.edu
  8. C++ Inheritance. www.tutorialcup.com
  9. Bjarne Stroustrup. The Design and Evolution of C++, 417. o. 
  10. Herbert Schildt. The complete reference C++. Tata McGrawhill Education Private Limited, 417. o. (2003). ISBN 978-0-07-053246-5 
  11. E Balagurusamy. Object Orientedprogramming With C++. Tata McGrawhill Education Pvt. Ltd., 213. o. (2010). ISBN 978-0-07-066907-9 
  12. override(C# Reference)
  13. GotW #60: Exception-Safe Class Design, Part 2: Inheritance. Gotw.ca. (Hozzáférés: 2012. augusztus 15.)
  14. Dr. K. R. Venugopal, Rajkumar Buyya. Mastering C++. Tata McGrawhill Education Private Limited, 609. o. (2013). ISBN 9781259029943 
  15. Cook, Hill & Canning 1990.
  16. Mitchell, John. 10 "Concepts in object-oriented languages", Concepts in programming language. Cambridge, UK: Cambridge University Press, 287. o. (2002). ISBN 978-0-521-78098-8 
  17. a b c Holub, Allen: Why extends is evil, 2003. augusztus 1. [2019. február 24-i dátummal az eredetiből archiválva]. (Hozzáférés: 2015. március 10.)
  18. (1996) „Evolution of object behavior using context relations”. ACM SIGSOFT Software Engineering Notes 21 (6), 46. o. DOI:10.1145/250707.239108.  
  19. (1991) „Designing an object-oriented programming language with behavioural subtyping”. REX School/Workshop on the Foundations of Object-Oriented Languages 489: 60–90. doi:10.1007/BFb0019440. 

További olvasnivaló szerkesztés