4032 Mer intro arv - Animal

Lärandemål

  • Förstå innebörden av statisk (tidig, vid kompilering) och dynamisk (sen, vid köring) bindning, samt hur det påverkar kodens utseende.
  • Kunna använda nyckelorden virtual och override på avsett vis.

Introduktion

Detta exempel är en fortsättning på föregående exempel. I det här exemplet görs några förändringar i klasserna Animal, Cat, Cow och Dog. Övriga klasser är oförändrade.

Klassen Animal

Metoden Act markeras med virtual för att den ska kunna ersättas i en ärvande klass.

using System;
namespace Animal
{
  class Animal
  {
    protected int age;

    public Animal()
    {
      age = 1;
    }

    public virtual void Act() 
    { 
      Console.WriteLine("hej hej");
    }
  }
}

Klassen Cat

Metoden Act markeras med override för att berätta att denna metod ersätter metoden med samma namn i superklassen.

using System;
namespace Animal
{
  class Cat : Animal
  {
    //konstruktor
    public Cat(int anAge)
    {
      age = anAge;
    }
    public override void Act()
    {
      Console.WriteLine("mjau mjau");
    }
  }
}

Klasserna Cow och Dog

På samma sätt som Cat.

using System;
namespace Animal
{
  class Cow : Animal
  {
    //konstruktor
    public Cow(int anAge)
    {
      age = anAge;
    }
    public override void Act()
    {
      Console.WriteLine("mu muu");
    }
  }
}

using System;
namespace Animal
{
  class Dog : Animal
  {
    //konstruktor
    public Dog(int anAge)
    {
      age = anAge;
    }
    public override void Act()
    {
      Console.WriteLine("vov vov");
    }
  }
}

Klassen Zoo

Koden är oförändrad.

using System;
using System.Collections.Generic;
using System.Text;

namespace Animal
{
  class Zoo
  {
    private List<Animal> animals;

    public Zoo()
    {
      animals = new List<Animal>();

    }
    public void Add(Animal anAnimal)
    {
      animals.Add(anAnimal);
    }
    public void Run()
    {
      foreach (Animal djuret in animals)
      {
        djuret.Act();
      }
    }
  }
}

Klassen Program med metoden Main

Koden i klassen är oförändrad.

using System;
namespace Animal
{
  class Program
  {
    static void Main(string[] args)
    {
      Zoo zoo = new Zoo();
      zoo.Add(new Cat(3));
      zoo.Add(new Cat(1));
      zoo.Add(new Cat(3));
      zoo.Add(new Dog(4));
      zoo.Add(new Dog(12));
      zoo.Add(new Cow(7));
      zoo.Add(new Cow(7));
      zoo.Add(new Cow(7));
      zoo.Run();

      // Keep the console window open in debug mode.
      Console.WriteLine("Press any key to exit.");
      Console.ReadKey();
    }
  }
}

Körning av programmet ger utskriften:

mjau mjau
mjau mjau
mjau mjau
vov vov
vov vov
mu muu
mu muu
mu muu

Förklaring djuret.Act()

Nu kräver anropet

zoo.Run();

en förklaring. I metoden Run körs följande foreach-sling.

foreach (Animal djuret in animals)
{
  djuret.Act();
}

Första varvet i slingan är djuret ett objekt av klassen Cat. När koden körs anropar den metod Act som finns i klassen Cat. Detta kallas för dynamisk bindning. Det finns lite mer att berätta men vi sparar det till lite längre ner på sidan.

När koden kompileras har djuret i foreach-slingan datatypen Animal. Därför måste det finnas en metod Act i klassen Animal. Detta kallas statisk bindning.

Föregående exempel

Efter den senaste förklaringen kräver även föregående exempel en förklaring. Där fanns det ingen metod Act i klasserne Cat, Cow och Dog.

Statisk bindning

När koden kompileras godkänns foreach-slingan av samma anledning som ovan. Vi kan alltså inte ta bort metoden Act i klassen Animal. Då kompilerar inte foreach-slingan.

Dynamisk bindning

När första varvet i foreach-slingan körs innehåller djuret ett objekt av klassen Cat. Eftersom metoden Act inte finns implementerad i klassen Cat så letar datorn efter samma metod i överklassen Animal. Där finns metoden Act. Det är denna metod som körs.

Objektdiagram