Shadowed, je li stvarno C# nema makroe ili nexygo jednostavno ne zna za njih?
nexygo, ne izbegava se ponavljanje koda da bi se smanjilo kucanje (bar ne prevashodno), već da bi izmena jedne funkcionalnosti na jednom mestu bila izmena u celom programu.
Citat:
Shadowed: Nego, kako je u c++ reseno ako obe klase koje se nasledjuju funkciju sa istim imenom i potpisom?
E, vidi se da si pozaboravljao C++.
Ako klase A i B nasleđuju klasu C, a klasa D nasleđuje klase A i B i pritom klasa C ima metodu void foo(), onda će klasa D imati metode void A::foo() i void B::foo(). Ako je pak nasleđivanje klasa A i B iz klase C bilo virtuelno, onda će klasa D imati samo jednu metodu void foo().
E, sad, to vodi do niza problema zbog kojih su uvođeni interfejsi. Implementacija može biti takva da na primer pokazivač na klasu C pokazuje na prvi atribut klase C, a da toj adresi prethodi pokazivač na tabelu virtuelnih metoda (koji postoji i ulazi u veličinu podatka akko je potreban, tj. klasa ima virtuelnih metoda). Za klase A i B važiće isto to, tj. pokazivač na objekat će pokazivati na prvi atribut klase C, a nakon svih njih će slediti atributi izvedene klase. Dakle u klasi A idu prvo atributi klase C, pa atributi klase A i slično za B. E, sad dolazimo do klase D. Tu će ako nasleđivanje nije virtuelno ići atrubuti klase A (uključujući nasleđene atribute klase C), pa klase B (uključujući nasleđene atribute klase C), pa klase D.
Međutim, gde da smestimo pokazivač na tabelu virtuelnih metoda (recimo da ih klasa C ima)? Klasa D mora da bude konvertibilna u svoje bazne klase A i B. Ako je smestimo pre atributa klase A, imaćemo problem sa time što su ofseti atributa klase B pri konverziji D* u B*. Zapravo, svaka od tih klasa ima svoje metode, tj. u klasi D imamo duplikate članova od C (nasleđene kroz A i nasleđene kroz B), pa će zapravo objekat biti sačinjen od pokazivača na tabelu virtuelnih metoda od A, pa atributa od A (zajedno sa nasleđenim atributima iz C), pa pokazivača na tabelu virtuelnih metoda od B, pa atributa od B (zajedno sa nasleđenim atributima od C), pa atributa od D. Može klasa D da ima svoje virtuelne metode, ali oni su smešteni u tabele od A i B, koje nisu na istom mestu u memoriji kao obične tabele od A i B, pa se ne može tek tako poređenjem pokazivača na tabelu virtuelnih metoda utvrditi da li su izvedene iz iste klase, pa je dynamic_cast utoliko sporiji.
U slučaju virtuelnog izvođenja klasa A i B iz C moramo u primerku klase D imati samo jednu kopiju atributa klase C, a da D i dalje bude konvertibilna u A i B. Kako kada obe klase nasleđuju C, a ofset atributa od A i B u odnosu a C ne može da bude isti. Čim je klasama A i B rečeno da su virtuelno nasleđene iz C, one pre svojih atributa imaju pokazivač na tabelu virtuelnih atributa, tj. ofset od C. E, onda D može da se sklopi sa samo jednim primerkom C.
No, kod višestrukog nasleđivanja prilikom konverzije pokazivača dolazi do promene vrednosti pokazivača u smislu apsolutne adrese, tako da računar mora sa sigurnošću da zna kako to da uradi. Ako se za neku konverziju može zaključiti da je moguća i kako je izvesti u fazi prevođenja, onda se koristi brzi static_cast (tipično za konveryiju iz izvedene u osnovnu klasu), a u suprotnom je static_cast sintaksna greška. Ukoliko se u fazi prevođenja može zaključiti kako u fazi izvršavanja da se odredi da li je konverzija moguća i kako i da je u bar nekim slučajevima moguća, onda se može koristiti spori dynamic_cast. No, on može u fazi izvršavanja da ne uspe.
No, tu nismo ni dotakli problem brisanja objekata. Ako imam pokazivač na klasu A koji pokazuje na primerak od D, pa ga brišemo, on mora da bude brisan kao primerak od D, tj. objekat, mada je posmatran kao primerak od A mora imati svest o tome da je zapravo objekat tipa D.
Sve to vodi do komplikovanih pravila, koja se značajno pojednostavljuju ako je nasleđivanje jednostruko, osim u slučaju interfejsa.
Nije bitno koji su zaključci izvučeni, već kako se do njih došlo.