Inledning
Objektorienterad programmering har fördelen att man lättare kan bygga ut sina program, förfina dem, rätta till saker etc genom att helt enkelt lägga till nya klasser. Här kommer just arv in i bilden. Ett arv innebär att vi kan skapa klasser som ärver attribut (variabler) och metoder från någon annan klass. Vi kan på så sätt utgå från en befintlig konstruktion och bygga vidare på den.
Säg vi utgår från följande klass:
class Person
{
private string namn;
private string telefon;
public Person(string namn, string telefon)
{
this.namn = namn;
this.telefon = telefon;
}
public string GetNamn()
{
return namn;
}
public string GetTelefon()
{
return telefon;
}
}
Enkelt arv
I C# tillåts vi bara att ärva från en klass i taget. Detta kallas för enkelt arv. I andra programmeringsspråk (t ex C++) så kan vi däremot ärva från flera klasser samtidigt, detta kallas för multipelt arv. Den klass vi ärver från kallas superklasseller basklass, den klass som gör arvet kallas för subklass. I UML ser det ut såhär:
Pilen i bilden indikerar ett arv, dvs att subklassen ärver från basklassen.
Klassen Person (se ovan) kan vi göra objekt av om och om igen men vi kan även utöka och skapa en mer detaljerad klass av Person. Säg att vi vill göra en klass Student. Student är ju också en person, då borde vi kunna använda oss av de egenskaper som klassen Person redan har. Vi behöver alltså inte skriva samma saker som vi redan gjort i klassen Personutan vi kan utöka och skapa klassen Student genom ett arv! Se exempel
class Student : Person
{
int inskrivningsår;
bool betaldKåravgift;
public Student(string n,string t,int år,bool betalat): base(n,t)
{
inskrivningsår = år;
betaldKåravgift = betalat;
}
public void PrintInfo()
{
Console.WriteLine("Namn: " + base.GetNamn() );
Console.WriteLine("TelNr: " + base.GetTelefon());
if(betaldKåravgift)
{
Console.WriteLine("Kåravgiften är betald!");
}
}
}
Genom att använda arv räcker det med att lägga till de egenskaper som är unika för en student.
Med kolonet (:) har vi här talat om att Student är en subklass till Person (rad 1). Person har därmed också blivit en superklass. Nyckelordet base refererar till basklassobjektet, liknande this, men ”som om” det vore ett objekt direkt ur superklassen, vilket gör att vi direkt kan använda de egenskaper som definierats i superklassen. Nedan är UML representationen av klasserna:
I UML markerar vi arvet genom en triangel med spetsen mot superklassen, samt en heldragen linje till subklassen.
I Student-konstruktorn återanvänder vi superklassens konstruktor för att slippa återupprepa tilldelningar utav de attribut vi ärvt från Person (se rad 6 ovan). När en student skapas så skapas det ju också en person. Logiskt? Man kan då ange vilken konstruktor i basklassen (Person) som ska användas när man skapar en student genom att skriva : base(parameter1, …) efter konstruktorn i subklassen (student). Anger man ingen basklass-konstruktor så utgår man ifrån att det finns en standardkonstruktor i basklassen. Här kommer du att få problem om det inte finns en sådan, då måste du veta hur du ska skriva för att ange vilken konstruktor som ska användas.
static void Main(string[] args)
{
Student s = new Student("Lisa", "123454", 2005, true);
string n = s.GetNamn();
s.PrintInfo();
}
När vi har skapat ett objekt av Student så upptäcker vi att vi kan använda både metoderna GetNamn() (från superklassen) och metoden PrintInfo() (från subklassen).
Protected
Vi har tidigare pratat om innebörden av private och public. Där public anger att metoderna och attributen är åtkomliga utifrån objektet/klassen i sig, och private har innebörden att metoder/attribut endast år åtkomliga inom den aktuella klassen.
När vi har ett arv mellan klasser så finns det en tredje grad av synlighet, nämligen protected. Denna variant har bara någon betydelse om vi har ett arv, annars fungerar den som private.
Innebörden av protected är att metoder och attribut fungerar som private, fast med det undantag att subklasser även får använda metoder/attribut som är definierade som protected. Man kan säga att inom familjen så är de åtkomliga. Vi tar ett litet exempel:
class MyBaseClass
{
private void Foo1()
{
}
protected void Foo2()
{
}
public void Foo3()
{
}
}
class MySubClass : MyBaseClass
{
public void DoSomething()
{
base.Foo2();
base.Foo3();
}
Om jag skapat objekt av klasserna MyBaseClass eller MySubClass så kan jag anropa metoden Foo3(). På objekt av typen MySubClass kan jag anropa DoSomething(). Detta pga att det är bara dessa metoder som är deklarerade public.
I metoden DoSomething() så kan basklassens metoder, Foo2() och Foo3(), anropas. Däremot går det inte att anropa Foo1() eftersom denna är deklarerad som private. Foo2() får jag anropa i subklassen eftersom denna metod är deklarerad som protected i superklassen och därmed gjord åtkomlig ”inom familjen”.
Videogenomgång
Vi har också en video som går igenom allt på ett något annorlunda vis än vad texten gör.
Övningar
Övning 1
Skapa en klass Tärning som ska fungera som en tärning. Den ska ha endast en konstruktor som tar hur många sidor tärningen ska ha. Du ska sedan kunna anropa en metod Kasta() som ska returnera ett slumpmässigt värde mellan 1 och antalet sidor på tärningen.Skriv klassen samt ett kort program som demonstrerar att klassen fungerar som den ska. Gör därefter ett UML-diagram över klassen Tärning.
Övning 2
Skapa klasserna i UML-diagrammet. Metoden GetInfo() ska returnera en beskrivning av den aktuella Creature (med Name, Health & Shield). Metoden Attack() i subklasserna kan skriva ut något i stil med : ”Knight {Name} attacks with {Weapon}” eller ”{Color} dragon attacks with fire”.
Skapa sedan ett program som demonstrerar att klasserna fungerar.
Övning 3
(om ni är bekanta med Windows Forms)Skapa ett Windows Forms projekt och skapa en ny klass ”MultiLineTextBox”. Klassen ska ärva från TextBox. Sätt vissa egenskaper från klassen TextBox i din MultiLineTexBox så att de på så vis får ett nytt standard-värde, t.ex. i konstruktorn.
Sätt MultiLine = true, Size = 150;50, BackColor = valfri trevlig färg (ej vit). Använd sedan en MultiLineTextBox i ditt program.
Viktiga begrepp
- enkelt arv
- multipelt arv
- superklass
- basklass
- subklass