UJEP materiály

Polymorfismus

Statický polymorfismus

Přetypování

Problém č. 1

Máme třídu Digit a chceme zařídit konverzi na typ int. Jsou 3 způsoby, jak to řešit:

  1. int(Digit) - přetypovací konstruktor (nelze u int, protože je to vestavěný typ)
  2. instanční metoda na třídě Digit (.ToInt)
  3. přetypovací operátor
public readonly struct Digit
{
    private readonly byte digit;

    public Digit(byte digit)
    {
        if (digit > 9)
        {
            throw new ArgumentOutOfRangeException(nameof(digit), "Digit cannot be greater than nine.");
        }
        this.digit = digit;
    }

    public static implicit operator byte(Digit d) => d.digit;
    public static explicit operator Digit(byte b) => new Digit(b);

    public override string ToString() => $"{digit}";
}

Přetěžování

double Sin(double x);
double Sin(int x);
public class Zlomek
{
    // Zastupuje konstruktor bez parametrů, s jedním parametrem a se dvěma parametry
    public Zlomek(int citatel = 0, int jmenovatel = 1) { }
}

Generické typy (Generics)

List<T> = generický typ, který má jeden typový parametr a jmenuje se List

Tuple<T1>
Tuple<T1, T2>
Tuple<T1, T2, T3>

// Specializace = dosazení za typové parametry, tak dostaneme tzv. konkrétní typ, což je typicky třída (např. )
List<int>
Tuple<int, int>
C# generika = specializace za překladu

List<T>, Add(T item) - když udělám List<int>, tak překladač vygeneruje metody s T parametrem se zvoleným typovým parametrem (tedy int)

Fáze překladu

  1. Vlastní překlad - kontrola generických typů
  2. Překlad před během - bytecode
  3. Překlad bytecode do strojového kódu (JIT, AOT)
    • JIT (Just in Time) = každou funkci při prvním volání přeloží, a pak už ji nepřekládá
    • AOT (Ahead of Time) = přeloží vše dopředu
  4. Specializace generických typů (generika zmizí, jsou nahrazeny a přeloženy pro konkrétní kód, proto generika nejsou pomalejší než negenerické metody)
  5. Běh (runtime)

Dynamický polymorfismus

Dědičnost

public override string Hlas() { } // předefinování
public new string Hlas() { } // zastínění (měli bychom se mu vyhýbat, jen v případě kolize)
třída A: metody x, y
třída B dědí z A: dědí metody x, y a přidává z
třída A: přidá metodu z
public abstract class Zvire
{
    public abstract string Hlas();

    public virtual string Jmeno() // dovolujeme předefinování, kdybychom vynechali, tak to předefinovat potomkem nelze
    {
        return "";
    }
}

public class Pes : Zvire
{
    public override string Hlas()
    {
        return "Haf";
    }
}

Zvire z = new Pes();
z.Hlas();  // zavolá se metoda Hlas ze třídy Pes
z.Jmeno(); // zavolá se metoda Jmeno ze třídy Zvire

Interface

public interface IFlyable
{
    void TakeOff();
    void Land();
    int Altitude { get; }
}

Duck polymorfismus