Arv (eng. inheritance ) - begreppet objektorienterad programmering , enligt vilket en abstrakt datatyp kan ärva data och funktionalitet av någon befintlig typ, vilket underlättar återanvändning av programvarukomponenter .
I objektorienterad programmering , sedan Simula 67 , kallas abstrakta datatyper för klasser .
Superklass ( eng. superklass ), förälderklass ( eng. förälderklass ), förfader, förälder eller superklass - en klass som producerar arv i underklasser, det vill säga en klass som andra klasser ärver från. En superklass kan vara en underklass, en basklass, en abstrakt klass och ett gränssnitt.
Underklass ( eng. underklass ), härledd klass ( eng. härledd klass ), barnklass ( eng. barnklass ), ättlingklass, efterföljande klass eller implementeringsklass - en klass som ärvts från en superklass eller gränssnitt, det vill säga en klass som definieras genom nedärvning från annan klass eller flera sådana klasser. En underklass kan vara en superklass.
En basklass är en klass som är överst i klassarvshierarkin och längst ner i underklassträdet, det vill säga att den inte är en underklass och inte ärver från andra superklasser eller gränssnitt. Basklassen kan vara en abstrakt klass och ett gränssnitt. Alla icke-basklasser är en underklass.
Ett gränssnitt är en struktur som definierar ett rent klassgränssnitt bestående av abstrakta metoder. Gränssnitt deltar i arvshierarkin av klasser och gränssnitt.
Ett supergränssnitt ( eng. supergränssnitt ) eller ett förfadergränssnitt är en analog till en superklass i arvshierarkin, det vill säga det är ett gränssnitt som ärver i underklasser och undergränssnitt.
Ett efterkommande gränssnitt, härlett gränssnitt eller härlett gränssnitt är en analog av en underklass i arvshierarkin av gränssnitt, dvs det är ett gränssnitt som ärvts från ett eller flera supergränssnitt.
Ett basgränssnitt är motsvarigheten till en basklass i arvshierarkin av gränssnitt, dvs det är gränssnittet överst i arvshierarkin.
En arvshierarki eller klasshierarki är ett träd vars element är klasser och gränssnitt.
Arv är en mekanism för kodåteranvändning (engelsk kodåteranvändning ) och bidrar till den oberoende expansionen av programvara genom öppna klasser (engelska publika klasser) och gränssnitt (engelska gränssnitt). Att ställa in ett arvsförhållande mellan klasser genererar en klasshierarki.
Arv identifieras ofta med subtyping polymorfism :
Trots ovanstående anmärkning är arv en allmänt använd mekanism för att etablera ett är -ett förhållande. Vissa programmeringsspråk är överens om arv och subtyp polymorfism (mest statiskt skrivna språk som C++ , C# , Java och Scala ) medan andra delar ovanstående koncept.
Arv – även i programmeringsspråk som stöder användningen av arv som en mekanism för subtyp polymorfism – garanterar inte subtyp beteendepolymorfism; se: "The Substitution Principle" av Barbara Liskov .
"Enkelt" arv, ibland kallat enkelarv, beskriver förhållandet mellan två klasser, varav den ena ärver den andra. Många klasser kan härröra från en enda klass, men trots detta förblir denna typ av relation "enkel" arv.
Abstrakta klasser och objektskapandeFör vissa programmeringsspråk är följande koncept giltigt.
Det finns "abstrakta" klasser (deklarerade som sådana godtyckligt eller på grund av de abstrakta metoder som tilldelats dem ); de kan beskrivas som att de har fält och metoder . Skapandet av objekt (instanser) innebär konkretisering , endast tillämplig på icke-abstrakta klasser (inklusive icke-abstrakta ättlingar till abstrakta), vars representanter, som ett resultat, kommer att vara de skapade objekten.
Exempel: Låt basklassen "Anställd vid universitetet ", från vilken klasserna " Forskarstuderande " och " professor " ärvs, vara abstrakt. Vanliga fält och funktioner för klasser (till exempel fältet "Födelseår") kan beskrivas i basklassen. Och programmet kommer att skapa objekt av endast härledda klasser: "Postgraduate student" och "Professor"; det brukar inte vara meningsfullt att skapa objekt av basklasser.
Med multipelt arv kan en klass ha mer än en förälder. I det här fallet ärver klassen alla förfäders metoder . Fördelen med detta tillvägagångssätt är större flexibilitet.
Multipelt arv är implementerat i C++ . Andra språk som tillhandahåller denna funktion inkluderar Python och Eiffel . Multipelarv stöds i UML .
Multipelt arv är en potentiell källa till fel som kan uppstå av att ha samma metodnamn i förfäder. I språk som är positionerade som efterföljare till C++ ( Java , C# och andra), beslutades det att överge flera arv till förmån för gränssnitt . Du kan nästan alltid göra utan att använda denna mekanism. Men om ett sådant behov ändå uppstod, för att lösa konflikter i användningen av ärvda metoder med samma namn, är det till exempel möjligt att tillämpa synlighetsförlängningsoperationen - "::" - att anropa en specifik metod för en specifik förälder.
Ett försök att lösa problemet med att ha samma metodnamn i förfäder gjordes på Eiffelspråket , där det, när man beskriver en ny klass, är nödvändigt att uttryckligen ange de importerade medlemmarna i var och en av de ärvda klasserna och deras namn i barnklass.
De flesta moderna objektorienterade programmeringsspråk ( C# , Java , Delphi och andra) stöder möjligheten att samtidigt ärva från en förfaderklass och implementera metoder för flera gränssnitt av samma klass. Denna mekanism gör att du till stor del kan ersätta flera arv - gränssnittsmetoder måste uttryckligen omdefinieras, vilket eliminerar fel när man ärver funktionaliteten för samma metoder för olika förfäderklasser.
I ett antal programmeringsspråk ärver alla klasser, antingen explicit eller implicit, från någon basklass. Smalltalk var ett av de första språken som använde detta koncept. Dessa språk inkluderar även: Objective-C (klass NSObject), Perl ( UNIVERSAL), Eiffel ( ANY), Java ( java.lang.Object), C# ( System.Object), Delphi ( TObject), Scala ( Any).
Arv i C++ :
klassA { }; // Basklass klass B : offentlig A {}; // Offentligt arv klass C : skyddad A {}; // Skyddad arvsklass Z : privat A { }; // Privat arvDet finns tre typer av arv i C++ : offentlig , skyddad , privat . Åtkomstspecifikationer för basklassmedlemmar ändras i avkomlingar enligt följande:
En av de största fördelarna med offentligt arv är att en pekare till härledda klasser implicit kan konverteras till en pekare till basklassen, så för exemplet ovan kan du skriva:
A * a = newB ( );Denna intressanta funktion öppnar för möjligheten till dynamisk typidentifiering (RTTI).
För att använda arvsmekanismen i Delphiclass måste du ange förfaderklassen i klassdeklarationen inom parentes :
Förfader:
TAncestor = klass privat skyddad offentlig // Virtuell procedur VirtualProcedure ; virtuell ; abstrakt ; procedur StaticProcedure ; slut ;Arvinge:
TDescendant = klass ( TAncestor ) privat skyddad offentlig // Virtuell procedur åsidosättande procedur VirtualProcedure ; åsidosätta ; procedur StaticProcedure ; slut ;Absolut alla klasser i Delphi är ättlingar till TObject. Om en förfaderklass inte specificeras, antas den nya klassen vara en direkt ättling till TObject.
Multipelt arv i Delphi stöds initialt inte i princip, men för de som inte kan klara sig utan det finns det fortfarande sådana möjligheter, till exempel genom att använda hjälpklasser (Сlass Helpers).
Python stöder både enkel- och multipelarv. Vid åtkomst till ett attribut sker visning av härledda klasser i ordningen för metodupplösningsordning (MRO ) [1] .
klass Ancestor1 ( objekt ): # Ancestor-1 def m1 ( self ): pass class Ancestor2 ( object ): # Ancestor-2 def m1 ( self ): pass class Descendant ( Ancestor1 , Ancestor2 ): # Descendant def m2 ( self ): passera d = Descendant () # Instans utskrift d . __klass__ . __mro__ # Metodupplösningsordning: ( < klass ' __main__ . Descendant '>, <klass ' __main__ . Ancestor1 '>, <klass ' __main__ . Ancestor2 '>, <typ ' objekt '>)Från och med Python 2.2 samexisterar "klassiska" klasser och "nya" klasser i språket. De senare är arvingar object. "Klassiska" klasser kommer att stödjas upp till version 2.6, men tas bort från språket i Python 3.0.
Multipelt arv används i Python, särskilt för att introducera inblandningsklasser i huvudklassen .
För att använda arvsmekanismen i PHPextends är det nödvändigt att ange ordet och namnet på förfaderklassen efter namnet på den deklarerade efterföljarklassen i klassdeklarationen :
klass Descendant utökar Ancestor { }Om den härledda klassen överlappar förfadermetoderna kan förfadermetoderna nås med hjälp av parent:
class A { function example () { echo "Metod A::example() anropad.<br /> \n " ; } } klass B utökar A { function example () { echo "Metod B::example() anropad.<br /> \n " ; förälder :: exempel (); } }Det är möjligt att förhindra en härledd klass från att åsidosätta en förfaders metoder; för att göra detta måste du ange nyckelordet final:
class A { final function example () { echo "Metod A::example() anropad.<br /> \n " ; } } klass B utökar A { funktionsexempel () { //kommer att ge ett felförälder :: exempel ( ) ; //och kommer aldrig att köras } }För att hänvisa till konstruktorn för den överordnade klassen under nedärvning är det nödvändigt att den underordnade klassen specificerar i konstruktorn parent::__construct();[2]
Gränssnittet deklarerar metoder som kommer att vara synliga utanför klassen (public).
Interna metoder kan implementeras utan gränssnitt. För att deklarera ytterligare egenskaper, använd interface-extension i implementeringsfilen.
Alla metoder i Objective-C är virtuella.
Ett exempel på arv från en klass och två gränssnitt :
public class A { } public interface I1 { } public interface I2 { } public class B utökar A implementerar I1 , I2 { }Ett direktiv finali en klassdeklaration gör det omöjligt att ärva från det.
Ett exempel på arv från en klass och två gränssnitt :
public class A { } public interface I1 { } public interface I2 { } public class B : A , I1 , I2 { }Arvning från typskrivna klasser kan göras genom att ange en fast typ, eller genom att överföra en typvariabel till en ärvd klass:
public class A < T > { } public class B : A < int > { } public class B2 < T > : A < T > { }Det är också möjligt att ärva kapslade klasser från klasser som innehåller dem:
klass A // standardklass A är intern, inte offentlig klass B kan inte vara offentlig { klass B : A { } }Ett direktiv sealedi en klassdeklaration gör det omöjligt att ärva från det. [3]
Klassen Parentär förfader till klassen Childvars metod åsidosätts public_method.
barn = Barn . nybarn . _ public_method #=> "Omdefinierad offentlig metod" underordnad . call_private_method #=> "Ancestors privata metod: Privat metod"En förfaders privata metoder kan kallas från ättlingar.
Klassen Parentär förfader till klassen Childvars metod åsidosätts publicMethod.
JavaScript använder prototypiskt arv.
I C++ anropas konstruktörer sekventiellt under arv från den tidigaste förfadern till det senaste barnet, och vice versa, destruktörer anropas från det senaste barnet till den tidigaste förfadern.
classFirst _ { offentliga : First () { cout << ">>Första konstruktör" << endl ; } ~ First () { cout << ">>First destructor" << endl ; } }; klass Andra : offentlig först { offentliga : Andra () { cout << ">Andra konstruktör" << endl ; } ~ Andra () { cout << ">Andra destruktören" << endl ; } }; klass Tredje : offentlig Tvåa { offentliga : Third () { cout << "Tredje konstruktör" << endl ; } ~ Third () { cout << "Third destructor" << endl ; } }; // kodexekvering Third * th = new Third (); ta bort th ; // output resultat /* >>Första konstruktör >Andra konstruktör Tredje konstruktör Tredje destruktören >Andra destruktören >>Första destruktören */