Bookmark and Share

Svårighetsgrad
Svårighetsgrad
Betyg (7 röster)
BetygBetygBetygBetygBetyg
 

Polymorfism

Inledning

Ett begrepp som är starkt förankrat i del flesta kursplaner är just polymorfism. Detta är ett begrepp som finns inom objektorienterade språk men som kan te sig olika ut beroende på språk. Ordet "polymorf" härstammar från grekiskan och betyder något i stil med "mångformig".

Polymorfa variabler

Detta gäller för variabler som är av referenstyp. Referenstyp innebär att variabeln i sig inte behöver innehålla något värde utan refererar till ett objekt eller en annan variabel. Motsatsen är så kallade variabler av värdetyp. Vanliga variabler av värdetyp är:

Variabler av referenstyp är objekt av klasser som alla skapats med nyckelordet class. Till dessa ingår även alla vektorer. Observera alltså att om ni gör en vektor av någon vanlig värdetyp, t ex int, så är alltså denna vektor av referenstyp.

Vad spelar detta för roll då? Jo när du skickar en variabel av värdetyp mellan metoder, som t ex inparameter eller returparameter, så skickas den "by value". Dvs. värdet som variabeln har skickas, inte själva variabeln i sig. Med referensvariabler är det däremot så att det är en referens till ett och samma objekt som skickas runt mellan metoderna. Skulle jag ändra något i referensvariabeln så ändrar jag själva "originalet". Vi tar ett kort exempel:

Exempel med värdetyp

Vårt objekt av Player är nu av värdetyp då den bygger på en struct. När objektet p1 skickas till metoden ChangeName så skapas det i samma ögonblick en kopia. Ändringarna gjorda i metoden påverkar inte objektet p1 på rad 19.

Exempel med referenstyp

Vårt objekt av Player är nu av referenstyp då den bygger på en class. Till metoden skickas nu en referens till objektet p1. Ändringarna gjorda i metoden påverkar nu objektet p1 på rad 19.

Statisk bindning

Hur fungerar då polymorfa variabler? Jo eftersom det finns en arvsmekanik inom OOP så innebär det att ett objekt kan vara av flera typer. Dels är objektet alltid av typen Object eftersom alla klasser i C# indirekt ärver från klassen Object. Klassen är kanske även uppbyggt av en eller flera basklasser och man kan då säga att objektet även är av dessa typer. Detta ger oss friheten att behandla objekt som om de vore av en viss klasstyp fastän de kanske i själva verket är objekt som är skapade från en subklass till klasstypen.

Vi provar med ett exempel:

Här har vi först an basklass, Player, och två klasser, Mage och Warrior som bygger på basklassen. På rad 35 skapar vi en List som ska hålla reda på alla våra spelare. Denna lista lagrar objekt av typen Player. På rad 37-39 skapar vi objekt och lägger till dem i listan. Det går alltså bra att lagra en Mage och en Warrior i listan då dessa också är av typen Player.

När vi på rad 41 loop'ar igenom listan så kommer alla objekt i listan att behandlas som om de vore av typen Player. Resultatet blir:

bild

Vad hände egentligen med Attack-metoderna i subklasserna? Jo de körs inte då vi behandlar alla objekt som Player. Nu körs bara implementationen i basklassen, dvs. Players Attack.

Vi ska nu visa att objekten som ligger lagrade i listan players faktiskt är en Player, en Mage och en Warrior.

Dynamisk bindning

Statisk bindning är som i exemplet ovan att varje klass/subklass har en alldeles egen implementation av en metod. Vilken metod som ska köras bestäms egentligen redan i det ögonblick som programmet kompileras. I vårt exempel ovan kan man säga att beroende på om jag ser objektet som en Player eller som en Mage så kommer olika implementationer att köras.

Resultatet blir:

bild

Vad händer nu? Jo inte samma sak givetvis. Helt plötsligt körs den implementation av Attack som finns i respektive subklass. Skickar jag en Mage som en Player så körs ändå klassen Mages implementation av Attack! Skickar jag ett objekt som bara är en Player så körs fortfarande Player-klassens implementation.

Detta fungerar eftersom vi använder override på metoden Attack i subklasserna och på så sätt omdefinierar hur den metoden ska fungera. Det spelar sedan ingen roll om vi ser på objekten, rätt implementation kommer ändå att köras. Detta kallas för dynamisk bindning.

För att detta ska fungera så behöver vi deklarera metoden Attack i basklassen som virtual. Det betyder att vi tillåter subklasser att definiera om metoden med en egen betydelse.

Dynamisk bindning kallas även sen bindning. Statisk bindning kallas även tidig bindning. Namnen i sig är nästan mer komplicerade än själva betydelsen av dem.

Viktiga begrepp

  • polymorfism
  • referenstyp
  • värdetyp
  • Statisk bindning
  • dynamisk bindning
  • sen bindning
  • tidig bindning

Kommentarer

1 inlägg