[C#] Ebben az esetben miért viselkedik másképp ha egy virtuális metódust felülírok az öröklött osztályban mintha a new kulcsszóval új meghatározást adnék neki?
Csináltam egy egyszerű példát a problémámra
A 37. és 38. sor miért nem ugyanazt("baseMethod") az eredményt adja vissza? Ha a szülő osztályomra castolom a gyerek osztályt miért a gyerek osztály metódusát hívja meg?
Ennek nincs köze hozzá. Az a baja, hogy a myBaseClass függvénye nem virtuális, így mindenképp az hívódik meg.
De nem értem, miért van virtual, override, és new össze-vissza a kódban?
Nem össze-vissza van, leírtam hogy mit szeretnék, egy származtatott osztály példányát használva meghívni a szülő osztály metódusát, erre csináltam két lehetséges megoldást - egy virtuális metódust és egy publikus metódust amit a new kulcsszóval a származtatott osztályban felülírok.
A problémám meg pont az, hogy a származtatott myBaseMethod metódust hívja meg, nem pedig az alap osztály myBaseMethod metódusát, és nem értem hogy miért, arra számítottam hogy castolás után gyakorlatilag megegyezik azzal mintha a származtatott osztályon belül azt írnám hogy base.myBaseMethod().
Könnyen lehet hogy valamit rosszul csinálok, nem értem a logikát mögötte, hogy konkrétan mi történik ilyenkor.
Mert VIRTUÁLIS a method. Ami azt jelenti jelen esetben, hogy tárol egy virtuális függvénytáblát, és minden objektumhoz hozzárendeli a megfelelő függvényt.
Ebben az esetben létrehozáskor eltárolja hogy a derivedclass method hol van, és utána azt hiába cast-olgatod, a virtuális táblában az a cím marad.
#3 Tudsz esetleg linkelni ezzel kapcsolatban dokumentációt? Nem találtam erre a konkrét esetre semmit, szeretném megérteni hogy miért így működik, hogy kívülről miért nem érhető el a szülő osztálya amikor a származtatott osztályon belül ennek semmi akadálya.
#4 egészen konkrétan semmi hasznosat nem írtál.
Polimorfizmus a szó, amit te keresel. Ha a hivatalos doksi érdekel, itt van:
A lényeg az, hogy van két osztályod, A és B, ahol B az A osztály leszármazott osztálya.
class A {}
class B : A {}
Ebben az esetben, ha a B osztályt példányosítod, csinálhatod így:
B obj = new B();
Van ez a fogalom, hogy statikus típus és dinamikus típus. A statikus típus azt jelenti, hogy fordítási időben milyen típusú kifejezés az obj változód, ami a példányt tárolja. A dinamikus típus pedig azt jelenti, hogy futási időben valójában milyen típusú objektum áll mögötte.
B obj; - ez a változódeklaráció eldönti, hogy az "obj" változód statikus típusa "B" lesz. Vagyis minden olyan tagot, amivel a B osztály rendelkezik, látni fogod.
new B() - ez a példányosító kifejezés pedig azt jelenti, hogy az "obj" változód mögött egy "B" objektum fog szerepelni - vagyis a dinamikus típusa "B" lesz.
A dolog akkor lesz érdekes, amikor rájössz arra, hogy az öröklődés miatt valójában ezt is megteheted:
A obj = new B();
Ezt azért teheted meg, mert a B osztály az A osztály leszármazottja - vagyis az öröklődés miatt tud minden olyan dolgot, amit az A is tud.
Ebben az esetben viszont az obj változód statikus típusa A lesz, de a dinamikus típusa B. És ez felvet két érdekes helyzetet.
Az egyik helyzet az, hogy van az A-ban egy virtual vagy override kulcsszóval megjelölt metódus, amit a B-ben override-olok:
class A {
public virtual void DoSomething() => Console.WriteLine(nameof(A));
}
class B : A {
public override void DoSomething() => Console.WriteLine(nameof(B));
}
A obj = new B();
obj.DoSomething();
Ebben az esetben a kimenet B lesz, mivel override esetében mindig a dinamikus típust kell figyelembe venni. Ezért fut le a B.DoSomething().
New kulcsszó esetén pedig az a szabály, hogy mindig a statikus típust kell figyelned, mivel nem felüldefiniál egy deklarációt, hanem csak elrejti azt.
class A {
public virtual void DoSomething() => Console.WriteLine(nameof(A)); //a virtualnak nincs hatása ebben az esetben
}
class B : A {
public new void DoSomething() => Console.WriteLine(nameof(B));
}
A obj = new B();
obj.DoSomething();
A kimenet A lesz.
Ugyanez a szabály vonatkozik arra az esetre is, amikor osztályon belül vagy:
class A {
public void DoSomething() => Console.WriteLine(Get());
public virtual string Get() => nameof(A);
}
class B : A {
public override string Get() => nameof(B);
}
A obj = new B();
obj.DoSomething(); //A kimenet "B"
New kulcsszó esetén pedig:
class A {
public void DoSomething() => Console.WriteLine(Get()); //a this objektum statikus típusa A
public virtual string Get() => nameof(A);
}
class B : A {
public new string Get() => nameof(B);
}
A obj = new B();
obj.DoSomething(); //A kimenet "A"
Kapcsolódó kérdések:
Minden jog fenntartva © 2025, www.gyakorikerdesek.hu
GYIK | Szabályzat | Jogi nyilatkozat | Adatvédelem | Cookie beállítások | WebMinute Kft. | Facebook | Kapcsolat: info(kukac)gyakorikerdesek.hu
Ha kifogással szeretne élni valamely tartalommal kapcsolatban, kérjük jelezze e-mailes elérhetőségünkön!