Što je rano i kasno uvezivanje? Razlika između metoda nadjačavanja i skrivanja. Dizajneri. Zadržane riječi super i ovo. Inicijalizacijski blokovi

10.11.2019 Programi

Da biste saznali koja je razlika između rano (statično) I kasno (dinamički) vezivanje u Javi, morate prvo razumjeti što je to vezivanje . Povezivanje znači da postoji veza između veze i koda. Na primjer, varijabla koju referirate povezana je s kodom u kojem je definirana. Isto tako, metoda koja se poziva vezana je za mjesto u kodu gdje je definirana.

Postoje dvije vrste povezivanja metoda u jeziku Java: rano povezivanje (također se naziva statičko) i kasno povezivanje (odnosno dinamičko) vezivanje . Pozivanje metode u Javi znači da je metoda vezana za određeni kod, bilo u vrijeme kompilacije ili u vrijeme izvođenja, kada se program izvodi i kada se stvaraju objekti. Kao što ime sugerira, statičko povezivanje je po prirodi više statičko jer se događa tijekom kompilacije, što znači da kod "zna" koju metodu pozvati nakon kompilacije izvorni kod u Javi u datoteke klase. A budući da je ovo u ranoj fazi životni ciklus program se također naziva rano uvezivanje. S druge strane, dinamičko povezivanje događa se tijekom izvođenja, nakon što program pokrene Java Virtual Machine. U ovom slučaju, metodu koja će se pozvati određuje određeni objekt, tako da informacije nisu dostupne u vrijeme prevođenja jer se objekti stvaraju u vrijeme izvođenja. A budući da se to događa kasno u životnom ciklusu programa, to se u Javi naziva kasno vezanje. Pogledajmo još nekoliko razlika kako bismo ovo bolje razumjeli i također mogli odgovoriti na ovo vrlo popularno pitanje postavljeno u intervjuima za Java.

Rano i kasno uvezivanje u Javi

Postoje mnoge razlike između statičkog i dinamičkog vezivanja u Javi, ali najvažnije je kako ih JVM koristi. Jeste li se ikada zapitali kako JVM odlučuje koju će metodu pozvati kada u opsegu postoji više od jedne metode s istim imenom? Ako ste ikada koristili preopterećenje ili nadjačavanje metode, znate da u Javi možete imati više metoda s istim imenom. U slučaju Jave virtualni stroj JVM koristi i statičko i dinamičko vezanje za odabir željene metode.

Primjer statičkog i dinamičkog povezivanja u Javi

U ovom programu vidjet ćete da se vezanje virtualnih metoda ne događa u vrijeme kompajliranja korištenjem statičkog vezivanja, budući da bi to pozvalo metodu iz superklase, kao što se događa sa statičkim metodama koje su rano vezane. Ako se pozove metoda iz podklase, tada je određeni objekt korišten za vezanje funkcije tijekom izvođenja, a time i za vezanje virtualne funkcije koristi se dinamičko povezivanje. javna klasa Main ( public static void main (String args) ( // Primjer statičkog i dinamičkog vezivanja u Javi Osiguranje trenutno = novo CarInsurance () ; // Vezanje temeljeno na dinamičkom objektu int premija = trenutno. premija(); // Statičko uvezivanje na temelju klase Kategorija niza = trenutna. kategorija(); Sustav. van. println("premium: " + premium); Sustav. van. println("kategorija: " + kategorija) ; ) ) klasa Osiguranje ( public static final int LOW = 100 ; public int premium () ( return LOW; ) public static String category () ( return "Insurance" ; ) ) class CarInsurance extends Insurance ( public static final int HIGH = 200 ; public int premium () ( return HIGH; ) public static String category () ( return "Car Insurance" ; ) ) Rezultati izvršenja: premium : 200 category : Insurance Kao što vidite, pozivanje metode premium() rezultiralo je izvršenjem metoda iz potklase, dok je pozivanje metode category() rezultiralo izvršenjem metode nadklase. To je zato što je premium() virtualna metoda koja se rješava pomoću kasni uvez, dok je category(). statička metoda, koji se rješava korištenjem statičkog povezivanja u vrijeme kompajliranja prema nazivu klase.
Zanima vas čitanje o Javi? Pridružite se grupi!

Razlike između ranog i kasnog vezivanja u Javi

Sada kada znate kako Java veže pozive metoda i kako funkcionira statičko i dinamičko vezivanje, ponovimo ključne razlike između ranog i kasnog vezivanja u Javi:
  1. Statičko povezivanje događa se tijekom kompajliranja, dok se dinamičko povezivanje događa tijekom izvođenja.

  2. Budući da se statičko povezivanje događa rano u životnom ciklusu programa, naziva se rano povezivanje. Slično tome, dinamičko vezanje također se naziva kasno vezanje jer se događa kasnije u izvođenju programa.

  3. Statičko vezanje koristi se u jeziku Java za rješavanje preopterećenih metoda, dok se dinamičko vezivanje koristi u jeziku Java za rješavanje nadjačanih metoda.

  4. Isto tako, privatne, statičke i terminalne metode rješavaju se korištenjem statičkog povezivanja jer se ne mogu nadjačati, dok se sve virtualne metode rješavaju korištenjem dinamičkog povezivanja.

  5. U slučaju statičkog vezanja ne koriste se konkretni objekti, već informacija o tipu, odnosno tip referentne varijable se koristi za otkrivanje željene metode. S druge strane, dinamičko vezanje koristi određeni objekt za pronalaženje željene metode u Javi.
Evo dobre vježbe temeljene na konceptima statičkog i dinamičkog vezivanja u Javi. Možete li odgovoriti na pitanje: "Što će biti ispisano kada se izvrši sljedeći program?" Što će ovaj program ispisati? Zbirka, skup ili hashset? To je sve što smo vam htjeli reći o razlikama između rano (statično) I kasno (dinamički) uvezivanje u Javi. Ovo je jedan od najbolja pitanja za telefonski razgovor o jeziku Java, budući da pruža brojne mogućnosti provjere dubine znanja kandidata. Uvijek to zapamtite privatna , statički I završne metode komunicirati pomoću statičko uvezivanje , A virtualno – dinamički . Isto tako, najbolji primjer statičkog vezanja je preopterećenje metode, dok je nadjačavanje dinamičko.

2

Recimo da nije bilo funkcije Hello, a mi jednostavno pozivamo ob.display u osnovi, a zatim poziva funkciju prikaza klase B, a ne klase A.

Poziv za display() jednom postavlja kompilator na verziju definiranu u osnovnoj klasi. To se zove razrješenje poziva statičke funkcije ili statičko vezanje - poziv funkcije se predaje prije nego što se program izvrši. Ovo se ponekad naziva i ranim vezanjem jer je funkcija display() specificirana tijekom kompilacije programa.

Sada, kako može pozvati funkciju prikaza izvedene klase bez korištenja virtualne ključne riječi (kasno vezanje) prije funkcije prikaza u osnovnoj klasi?

Sada u ovom programu prosljeđivanje objekta kao poziva prema vrijednosti, poziva prema pokazivaču i poziva prema referenci na Hello funkciju radi dobro. Sada, ako koristimo polimorfizam i želimo prikazati funkciju članicu izvedene klase ako je pozvana, moramo dodati ključna riječ virtualni prije funkcije mapiranja baze podataka. Ako proslijedite vrijednost objekta kada pozivate pomoću pokazivača i pozivate po referenci, to je poziv funkcije u izvedenoj klasi, ali ako prosljeđujete objekt po vrijednosti, to nije slučaj zašto je to tako?>

Klasa A ( public: void display(); // virtualni void display() ( cout<< "Hey from A" <display() ) int main() ( B obj; Pozdrav(obj); // obj //&ob return 0; )

  • 2 odgovora
  • Sortiranje:

    Aktivnost

4

kako sada može pozvati funkciju prikaza izvedene klase bez korištenja virtualne ključne riječi (kasno vezanje) prije funkcije prikaza u osnovnoj klasi?

Nevirtualnu funkciju prevoditelj jednostavno rješava prema statičkom tipu objekta (ili reference ili pokazivača) koji poziva. Dakle, dati objekt izvedenog tipa, kao i referenca na njegov podobjekt:

Bb; A&a=b;

dobit ćete različite rezultate pozivanjem nevirtualne funkcije:

B.display(); // poziva se kao B a.display(); // naziva se A

Ako znate pravi tip, možete odrediti kako želite nazvati ovu verziju:

Static_cast (a).display(); // naziva se B

ali ono što bi bilo užasno pogrešno je da objekt a na koji se odnosi nema tip B .

Sada, ako koristimo polimorfizam i želimo mapirati funkciju članicu izvedene klase ako je pozvana, moramo dodati virtualnu ključnu riječ prije funkcije mapiranja u bazi.

Ispraviti. Ako funkciju učinite virtualnom, ona će se razriješiti tijekom izvođenja u skladu s dinamičkim tipom objekta, čak i ako koristite drugu referentnu vrstu ili pokazivač za pristup. Dakle, oba gornja primjera bi to nazvala B.

Ako proslijedimo vrijednost objekta pozivom po pokazivaču i pozivom po referenci, ona poziva funkciju u izvedenoj klasi, ali ako proslijedimo objekt po vrijednosti, to ne znači zašto je to slučaj?

Ako ga prođete po vrijednosti, onda vi rezanje na kriške njegovo: kopiranje samo A dijela objekta da bi se napravio novi objekt tipa A. Dakle, bez obzira na to je li ova funkcija virtualna, njezino pozivanje na ovom objektu odabrat će verziju A, budući da je to A i ništa osim A.

0

wikipedia kaže da se rezanje objekta događa jer nema prostora za pohranjivanje dodatnih izvedenih članova klase u superklasi, pa se reže. Zašto se rezanje objekata ne događa ako ga proslijeđujemo referencom ili pokazivačem? Zašto superklasa dobiva dodatni prostor za pohranu? -

VIRTUALNE FUNKCIJE_________________________________________________________________ 1

Rani i kasni uvez. Dinamički polimorfizam _______________________________________ 1

Virtualne funkcije _________________________________________________________________ 1 Virtualni destruktori __________________________________________________________________ 4 Apstraktne klase i čiste virtualne funkcije _____________________________________________ 5

VIRTUALNE FUNKCIJE

Rani i kasni uvez. Dinamički polimorfizam

C++ podržava polimorfizam na dva načina.

Prvo, podržan je tijekom kompilacije kroz preopterećenje funkcija i operatora. Ova vrsta polimorfizma naziva se statički polimorfizam, budući da se provodi i prije izvršenja

program, po rano povezivanje identifikatora funkcija s fizičkim adresama u fazi kompilacije i povezivanja.

Drugo, podržan je tijekom izvođenja programa kroz virtualne funkcije. Nakon što u programskom kodu naiđe na virtualni poziv funkcije, prevodilac (ili, točnije, povezivač) samo označava taj poziv, ostavljajući povezivanje identifikatora funkcije s njegovom adresom do faze izvršenja. Ovaj proces se zove kasni uvez.

Virtualna funkcija je funkcija čiji poziv (i radnje koje izvodi) ovisi o vrsti objekta na kojem se poziva. Objekt određuje koja se funkcija treba pozvati tijekom izvođenja programa. Ova vrsta polimorfizma naziva se dinamički polimorfizam.

osnova dinamički polimorfizam je mogućnost koju daje C++ da definira pokazivač na osnovnu klasu, koji će zapravo pokazivati ​​ne samo na objekt ove klase, već i na bilo koji objekt izvedene klase. Ova mogućnost dolazi putem nasljeđivanja jer je objekt izvedene klase uvijek objekt osnovne klase. U vrijeme prevođenja još nije poznato koji će objekt klase korisnik htjeti stvoriti, s obzirom na pokazivač na objekt osnovne klase. Takav pokazivač pridružuje se svom objektu samo tijekom izvođenja programa, odnosno dinamički. Klasa koja sadrži barem jednu virtualnu funkciju naziva se polimorfnom.

Za svaki polimorfni tip podataka, prevodilac stvara tablicu virtualnih funkcija i ugrađuje skriveni pokazivač na tu tablicu u svaki objekt ove klase. Sadrži adrese virtualnih funkcija odgovarajućeg objekta. Naziv pokazivača na tablicu virtualnih funkcija i naziv tablice ovise o implementaciji u pojedinom prevoditelju. Na primjer, u Visual C++ 6.0 ovaj pokazivač se zove vfptr, a tablica se zove vftable (od engleskog Virtual Function Table). Kompajler automatski ugrađuje dio koda na početak konstruktora polimorfne klase koji inicijalizira pokazivač na tablicu virtualnih funkcija. Ako se pozove virtualna funkcija, kod koji generira prevoditelj pronalazi pokazivač na tablicu virtualne funkcije, zatim traži tu tablicu i iz nje dohvaća adresu odgovarajuće funkcije. Nakon toga se vrši prijelaz na navedenu adresu i poziva se funkcija.

Podsjetimo se da se pri stvaranju objekta izvedene klase prvo poziva konstruktor njegove osnovne klase. U ovoj fazi kreira se tablica virtualnih funkcija, kao i pokazivač na nju. Nakon pozivanja konstruktora izvedene klase, pokazivač tablice virtualne funkcije postavlja se da upućuje na nadjačanu virtualnu funkciju (ako postoji) koja postoji za objekt te klase.

U tom smislu morate biti svjesni cijene koju morate platiti za mogućnost korištenja kasnog vezanja.

Budući da objekti s virtualnim funkcijama također moraju podržavati tablicu virtualnih funkcija, njihova uporaba uvijek dovodi do blagog povećanja troškova memorije i smanjenja performansi programa. Ako radite s malom klasom koju ne namjeravate koristiti kao osnovnu klasu za druge klase, tada nema smisla koristiti virtualne funkcije.

Virtualne funkcije

Funkcije čije je pozivno sučelje (tj. prototip) poznato, ali implementacija se ne može specificirati općenito, već se može definirati samo za specifične slučajeve, nazivaju se virtualnim (izraz koji znači da se funkcija može nadjačati u izvedenoj klasi) .

Virtualne funkcije su funkcije koje osiguravaju da se pozove ispravna funkcija na objektu, bez obzira koji se izraz koristi za pozivanje.

Pretpostavimo da osnovna klasa sadrži funkciju koja je deklarirana virtualnom, a izvedena klasa definira istu funkciju. U ovom slučaju, funkcija iz izvedene klase poziva se na objekte izvedene klase, čak i ako se poziva pomoću pokazivača ili reference na osnovnu klasu. Primjer:

klasa Koord

Osnovna koordinatna klasa

// osnovna koordinatna klasa

zaštićen:

// zaštićeni članovi klase

dvostruki x, y;

// koordinate

javnost:

// javni članovi klase

Coord() (x = 0; y = 0;)

// konstruktor osnovne klase

void Input();

// deklarira nevirtualnu funkciju

virtualna praznina Ispis();

// deklarira virtualnu funkciju

void Coord::Input()

// omogućuje unos koordinata s tipkovnice

cout<<"\tx=";

// unosi vrijednost x s tipkovnice

cout<<"\ty=";

// unosi y vrijednost s tipkovnice

void Coord::Print()

// prikazuje vrijednosti koordinata na ekranu

cout<<"\tx="<

Izvedena bodovna klasa

klasa Točka: publicCoord

// nasljednik koordinatne klase

char ime;

// ime točke

javnost:

// javni članovi klase

Točka (char N) : Koord () ( ime = N ; )

// poziva konstruktor osnovne klase

void Input();

void Ispis();

void Dot::Input()

// omogućuje unos koordinata točke s tipkovnice

char S = "Unesite koordinate točke";

CharToOem(S, S);

cout<

Koord::Ulaz();

void Dot::Print()

// prikazuje vrijednosti koordinata točke na ekranu

char S ="Koordinate točke";

CharToOem(S, S);

// pretvara niz znakova u ćirilicu

cout<

// prikazuje naslov i naziv točke

Koord::Ispis();

// poziva funkciju osnovne klase

klasa Vec: publicCoord

Izvedena vektorska klasa

// nasljednik koordinatne klase

char ime [3];

// naziv vektora

javnost:

// javni članovi klase

Vec (char * pName) : Coord () ( strncpy (name , pName , 3) ​​​​; name [ 2 ] = "\0" ; )

void Input();

// nadjačava nevirtualnu funkciju

void Ispis();

// nadjačava virtualnu funkciju

void Vec::Input()

// omogućuje unos vektorskih projekcija s tipkovnice

Predavanje 9 Virtualne funkcije 3

char S ="Unesite projekcije vektora";// deklarira i inicijalizira prompt niz

CharToOem(S, S);

// pretvara niz znakova u ćirilicu

cout<

// prikazuje upit i naziv vektora

Koord::Ulaz();

// poziva funkciju osnovne klase

void Vec::Ispis()

// prikazuje vrijednosti vektorskih projekcija na ekranu

char S = "Projekcije vektora";

// deklarira i inicijalizira redak zaglavlja

CharToOem(S, S);

// pretvara niz znakova u ćirilicu

cout<

// prikazuje naslov i naziv vektora

Koord::Ispis();

// poziva funkciju osnovne klase

U gornjem primjeru, deklarirana je osnovna klasa Coord i dvije izvedene klase Dot i Vec. Funkcija Print() u izvedenim klasama je virtualna jer je deklarirana virtualnom u osnovnoj klasi Coord. Funkcija Print() u izvedenim klasama Dot i Vec nadjačava funkciju osnovne klase. Ako izvedena klasa ne pruža nadjačanu implementaciju funkcije Print(), koristi se zadana implementacija iz osnovne klase.

Funkcija Input() proglašena je nevirtualnom u osnovnoj klasi Coord i nadjačana u izvedenim klasama Dot i Vec.

void main()

Coord* pC = new Coord();

// deklarira pokazivač na koordinate i dodjeljuje memoriju

Točka* pD = nova točka("D");

// deklarira pokazivač na točku i dodjeljuje memoriju

Vec* pV = novi Vec("V");

// deklarira pokazivač na vektor i dodjeljuje memoriju

pC->Ulaz () ;

pC->Ispis () ;

// poziva virtualnu funkciju Coord::Print()

// pokazivač na koordinate prima adresu objekta tipa točke

pC->Ulaz () ;

// poziva nevirtualnu funkciju Coord::Input()

pC->Ispis () ;

// poziva virtualnu funkciju Dot::Print()

// pokazivač na koordinate prima adresu objekta vektorskog tipa

pC->Ulaz () ;

// poziva nevirtualnu funkciju Coord::Input()

pC->Ispis () ;

// poziva virtualnu funkciju Vec::Print()

U gornjem primjeru, koordinatni pokazivač pC naizmjenično uzima vrijednosti adrese koordinatnih objekata, točke i vektora. Iako se tip pC pokazivača ne mijenja, on poziva različite virtualne funkcije ovisno o svojoj vrijednosti.

Kada koristite pokazivač osnovne klase koji zapravo pokazuje na objekt izvedene klase, poziva se nevirtualna funkcija osnovne klase.

Treba napomenuti da je operacija dodjele pC = pD, koja koristi operande različitih tipova (Coord* i Dot*) bez konverzije, moguća samo za pokazivač osnovne klase na lijevoj strani. Operacija obrnutog dodjeljivanja pD = pC nije važeća i uzrokuje sintaktičku pogrešku.

Kada se izvrši, program prikazuje:

Koordinate točke D:

Projekcije vektora V:

Pri pozivanju funkcije pomoću pokazivača i referenci primjenjuju se sljedeća pravila:

poziv virtualne funkcije rješava se prema tipu objekta čiju adresu pohranjuje pokazivač ili referenca;

poziv nevirtualne funkcije rješava se prema vrsti pokazivača ili reference.

Virtualne funkcije pozivaju se samo na objektima koji pripadaju određenoj klasi. Zato

Globalnu ili statičku funkciju ne možete proglasiti virtualnom. Virtualna ključna riječ može

Kasno ropstvo S COM komponente

Prije nego što izvršna datoteka klijenta može pozvati metode i svojstva objekta komponente, mora znati memorijske adrese tih metoda i svojstava. Postoje dvije različite tehnologije koje klijentski programi mogu koristiti za određivanje tih adresa.

Rano povezani programi uče adrese rano u procesu kompilacije/izvršenja—u vrijeme kompilacije. Kada se kompajlira program za rano vezivanje, prevodilac koristi biblioteku tipova komponente da uključi adrese metoda i svojstava komponente u klijentsku izvršnu datoteku tako da se adresama može pristupiti vrlo brzo i bez grešaka. Tehnologije COM interop o kojima se govori tako daleko koristiti rano vezanje.

Sa svoje strane, kasno povezani programi uče adrese svojstava i metoda kasno u procesu kompilacije/izvršenja. upravo u trenutku kada se ta svojstva i metode pozivaju. Kasno vezani kod obično pristupa klijentskim objektima putem temeljnih tipova podataka kao što je objekt i koristi vrijeme izvođenja za dinamičko određivanje adresa metoda. Iako kasno vezani kod dopušta korištenje nekih složenih tehnika programiranja kao što je polimorfizam, dolazi s nekim povezanim troškovima, koje ćemo uskoro vidjeti.

Ali prvo, provjerimo kako se kasno vezanje izvodi korištenjem refleksije u C# (Refleksija je način na koji kod koristi za vrijeme izvođenja kako bi odredio informacije o sučeljima klasa na strani poslužitelja; pogledajte Poglavlje 5.)

Prilikom kasnog povezivanja s COM objektom u C# programu, ne morate stvarati RCW za COM komponentu. Umjesto toga, poziva se metoda klase GetTypeFromProgID klase Type za instanciranje objekta koji predstavlja tip COM objekta. Klasa Type član je imenskog prostora System.Runtime.InteropServices, a u donjem kodu konfiguriramo objekt Type za istu COM komponentu pristupa podacima korištenu u prethodnim primjerima:


Tip objCustomerTableType;

Kada postoji Type objekt koji enkapsulira informacije o tipu COM objekta, koristi se za stvaranje instance samog COM objekta. To se postiže prosljeđivanjem Type objekta metodi CreateInstance klase Activator. CreateInstance stvara instancu COM objekta i vraća referencu kasnog povezivanja na njega, koja se može pohraniti u referencu tipa objekta.

objekt objCustomerTable;
objCustomerTable = Activator.CreateInstance(objCustomerTableType);

Nažalost, nije moguće pozvati metode izravno na referencu tipa object. Da biste mogli pristupiti COM objektu, morate koristiti metodu InvokeMember objekta Type koji je prvi kreiran. Kada se pozove metoda InvokeMember, prosljeđuje joj se referenca na COM objekt zajedno s nazivom COM metode koja se poziva, kao i niz objekata tipa svih ulaznih argumenata metode.

ObjCustomerTableType.InvokeMember("Delete", BindingFlags.InvokeMethod, null, objCustomerTable, aryInputArgs);

Ponovno se prisjetimo slijeda radnji:

1. Stvorite Type objekt za tip COM objekta koristeći metodu klase Type.GetTypeFromProgID() .

2. Koristite ovaj Type objekt za stvaranje COM objekta koristeći Activator.CreateInstance() .

3. Metode se pozivaju na COM objekt pozivanjem metode InvokeMember na Type objektu i prosljeđivanjem reference na objekt kao ulaznog argumenta. Ispod je primjer koda koji sve ovo kombinira u jedan blok:

koristeći System.Runtime.InteropServices;
Tip objCustomerTableType;
objekt objCustomerTable;
objCustomerTableType=Type.GetTypeFromProgID("DataAccess.CustomerTable");
objCustomerTable=Activator.CreateInstance(ObjCustomerTableType);
objCustomerTableType.InvokeMember("Delete", BindingFlags, InvokeMethod, null, objCustomerTable, aryInputArgs);
objCustomerTableType = Type.GetTypeFromProgID("DataAccess.CustomerTable");

Iako C# značajke kasnog vezanja izbjegavaju poteškoće RCW-a, postoje neki nedostaci povezani s njim.

Prvo: kasno uvezivanje može biti opasno. Kada se koristi rano vezanje, prevodilac može postaviti upit biblioteci tipova COM komponente kako bi osigurao da sve metode pozvane na COM objekte stvarno postoje. Uz kasno vezanje, ne postoji ništa što bi spriječilo grešku pri upisu u pozivu InvokeMember() da izazove pogrešku tijekom izvođenja.

Zadnja izmjena: 02.04.2019

Prethodno smo pogledali dva načina za promjenu funkcionalnosti metoda naslijeđenih od osnovne klase - skrivanje i nadjačavanje. Koja je razlika između ove dvije metode?

Nadjačavanje

Uzmimo primjer s nadjačavanjem metode:

Klasa Osoba ( public string FirstName ( get; set; ) public string LastName ( get; set; ) public Person(string firstName, string lastName) ( FirstName = firstName; LastName = lastName; ) public virtual void Display() ( Console.WriteLine ($"(FirstName) (LastName)"); ) ) class Employee: Person ( public string Company ( get; set; ) public Employee(string FirstName, string LastName, string Company) : base(firstName, lastName) ( Company = tvrtka; ) public override void Display() ( Console.WriteLine($"(FirstName) (LastName) runs in (Company)"); ) )

Kreirajmo također objekt Employee i proslijedimo ga varijabli tipa Person:

Osoba tom = novi zaposlenik ("Tom", "Smith", "Microsoft"); tom.Display(); // Tom Smith radi u Microsoftu

Sada dobivamo drugačiji rezultat nego sa skrivanjem. A kada se pozove tom.Display(), izvršava se implementacija metode Display iz klase Employee.

Za rad s virtualnim metodama, prevodilac generira tablicu virtualnih metoda (Virtual Method Table ili VMT). U njega su upisane adrese virtualnih metoda. Svaki razred ima svoju tablicu.

Kada se kreira objekt klase, prevodilac prosljeđuje poseban kod konstruktoru objekta koji povezuje objekt i VMT tablicu.

A kada se pozove virtualna metoda, adresa njene VMT tablice preuzima se iz objekta. Adresa metode se zatim dohvaća iz VMT-a i kontrola se prenosi na njega. Odnosno, proces odabira implementacije metode provodi se tijekom izvođenja programa. Ovo je zapravo način na koji se izvršava virtualna metoda. Imajte na umu da budući da runtime okruženje prvo treba dobiti adresu željene metode iz VMT tablice, to malo usporava izvođenje programa.

Prikrivanje

Sada uzmimo iste klase Osoba i Zaposlenik, ali umjesto nadjačavanja koristimo skrivanje:

Klasa Osoba ( public string FirstName ( get; set; ) public string LastName ( get; set; ) public Person(string firstName, string lastName) ( FirstName = firstName; LastName = lastName; ) public void Display() ( Console.WriteLine( $"(Ime) (Prezime)"); ) ) class Employee: Person ( public string Company ( get; set; ) public Employee(string FirstName, string LastName, string Company) : base(firstName, lastName) ( Company = company ; ) public new void Display() ( Console.WriteLine($"(FirstName) (LastName) runs in (Company)"); ) )

I da vidimo što se događa u sljedećem slučaju:

Osoba tom = novi zaposlenik ("Tom", "Smith", "Microsoft"); tom.Display(); //Tom Smith

Tom varijabla predstavlja tip osobe, ali pohranjuje referencu na objekt Employee. Međutim, prilikom pozivanja metode Display izvršit će se verzija metode koja je definirana u klasi Osoba, a ne u klasi Zaposlenik. Zašto? Klasa Employee ne nadjačava metodu Display naslijeđenu od osnovne klase, već zapravo definira novu metodu. Stoga, kada se pozove tom.Display(), poziva se metoda Display iz klase Person.