Poslao: 26 Jan 2006 23:54
|
offline
- Pridružio: 19 Maj 2005
- Poruke: 352
- Gde živiš: Sabac - Novi Sad
|
Pozdrav...
Da li bi neko mogao da mi da preciznu definiciju inkluzivnog polimorfizma i navede konkretan primer njegovog koriscenja...?
Drugo pitanje odnosi se na virtuelne funkcije, konkretno kako se realizuju u smislu stack, dinamicka memorija, masinski oblik. Zapravo sta se to desava koriscenjem ove funkcije.
Nadam se da ste me razumeli...
Inace trebaju mi sto precizniji odgovori, mogu mi biti od velikog znacaja...
Hvala
|
|
|
Registruj se da bi učestvovao u diskusiji. Registrovanim korisnicima se NE prikazuju reklame unutar poruka.
|
|
Poslao: 27 Jan 2006 03:22
|
offline
- bNasty

- Građanin
- Pridružio: 17 Mar 2004
- Poruke: 293
- Gde živiš: UK
|
Citat:Da li bi neko mogao da mi da preciznu definiciju inkluzivnog polimorfizma i navede konkretan primer njegovog koriscenja...?
Precizna definicija... ne znam da li tako neshto postoji, ali bilo koja definicija koju nadjesh u knjizi koja uchi OOP iz ugla software dizajna bi trebala da odradi posao.
U principu - Inclusive Polymorphism je ono shto smo koristili dugo u C++u (i u C#, Javi... koji to tek sada menjaju), a to je najprostije recheno - nasledjivanje (inheritance, ili subtyping). "Inclusive" je zato shto ukljuchuje u sebe deklaraciju naledjenog tipa (tj. proizvodi pod-tip generalnog tipa).
Kontrast toga je "parametarski polimorfizam", ono shto u C++u zovemo templates, ili 'generics' u C#-u, gde je polimorfizam, k'o shto mu ime kazhe, parametarski - ne postoji semantichko vezivanje za odredjeni tip, vec se vezivanje razreshava na sintaksnom nivou.
Tako nekako, najprostije recheno... sorry, ali za ultra-preciznu definiciju cesh morati da konsultujesh literaturu nekog od priznatih imena teorije softverskog dizajna, knjishke definicije uglavnom ne pamtim
Recimo, primer koji kombinuje ova dva pristupa u C++u:
template <class T> class ListElement
{ public : T* next; T* prev; };
class MyClass : public ListElement<MyClass>
{ /* ... */ };
Citat:Drugo pitanje odnosi se na virtuelne funkcije, konkretno kako se realizuju u smislu stack, dinamicka memorija, masinski oblik. Zapravo sta se to desava koriscenjem ove funkcije.
Na ovo pitanje ne postoji jedinstveni odgovor. Svaki compiler vendor je slobodan da implementira "virtual table" mehanizam kako zheli, postoje standardni metodi kojima se rukovode, ali implementacija svakog kompajlera je drugachija, narochito oko alociranja memorije, da ne pominjem "mashinski oblik".
Generalni princip je sledeci:
Kompajler za svaku klasu u hijerarhiji koja sadrzhi virtuelne funkcije (ukljuchujuci i destruktor) pravi "virtuelnu tabelu funkcija".
Kada se kreira instanca ovakve klase kompajler 'iza ledja' u sam objekar ugradjuje pointer na pomenutu tabelu virtuelnih funkcija (tzv. 'vfptr', zato je za virtuelne klase sizeof(klasa) vrednost VECA od prostog zbira velichine chlanova, jer klasa sadrzhi i ovaj pointer iako ga ne vidish).
Tabela virtuelnih funkcija sadrzhi nishta drugo do pointere na funkcije koje su preklopljene u toj klasi (klasi, ne objektu! jer svi objekti dele funkcije same klase).
Kada se pozove funkcija koja je virtuelna, i to recimo preko pointera na baznu klasu dok sam objekat pripada izvedenoj klasi, kompajler u run-time-u prvo pronalazi kojoj tachno klasi u hijerarhiji pripada dati pointer (implementacija ovoga je takodje zavisna od kompajlera), pa zatim pretrazhuje redom tabele virtuelnih funkcija u hijerarhiji dok ne nadje "najvishu" instancu preklopljene funkcije. Recimo, da je virtuelna funkcija definisana samo u baznoj klasi, ali ne i u izvedenim, kompajler ce proci kroz niz tabela virtuelnih funkcija dok ne nadje odgovarajucu funkciju, tj. u ovom sluchaju ce ici skroz do bazne klase, jer funkcija nije preklopljena ni u jednoj izvedenoj funkciji.
Huh, nadam se da ovo shto napisah nije suvishe nabacano i zamrsheno
Rekoh, ovo je generalni princip, niti je precizan niti obavezno i bezuslovno tachan, implementacija ima koliko god hocesh.
Btw, ako te zanima kako je to implementirano u Microsoft kompajlerima pochni odavde :
[Link mogu videti samo ulogovani korisnici]
... na dalje cesh se vec snaci
|
|
|
|
Poslao: 27 Jan 2006 22:53
|
offline
- Pridružio: 19 Maj 2005
- Poruke: 352
- Gde živiš: Sabac - Novi Sad
|
Citat:Recimo, primer koji kombinuje ova dva pristupa u C++u:
template <class T> class ListElement
{ public : T* next; T* prev; };
class MyClass : public ListElement<MyClass>
{ /* ... */ };
Nisam bas siguran da sam razumeo. Da li ovo znaci da je konkretna primena inkluzivnog polimorfizma bas template?
Inace veliko hvala i zadovoljan sam odgovorom...
|
|
|
|
|
Poslao: 28 Jan 2006 01:38
|
offline
- bNasty

- Građanin
- Pridružio: 17 Mar 2004
- Poruke: 293
- Gde živiš: UK
|
Citat:Nisam bas siguran da sam razumeo. Da li ovo znaci da je konkretna primena inkluzivnog polimorfizma bas template?
Ne, primer je bio tu da ilustruje primenu oba tipa nasledjivanja za konkretni problem (u gornjem sluchaju, kako generichki/parametarski definisati klasu kao element liste).
Inache, velika snaga C++a je bash u ovoj mogucnosti kombinovanja "obichnog" (inclusive) nasledjivanja (koje predstavlja semantichku vezu) i templejtovanog nasledjivanja (koje se razreshava chisto sintaksnom proverom), neshto shto ni mnogo mladji jezici nemaju, ili su dobili tek nedavno.
Recimo, sledeca deklaracija je josh jedan primer, veoma chesto korishcen u dizajnu biblioteka klasa (tz. "mixin", veoma mocno sredstvo u dizajnu) :
- template <class Baza> class Izvedena : public Baza
- {
- /* ... */
- };
Ovo jeste rudimentaran primer, ali sa ovakvim konstruktima ti odjednom postaje moguce da definishesh nasledjenu klasu BEZ ikakvog znanja o baznoj klasi, tj. mozhesh svoj dizajn klasa da posmatrash sa koje god hocesh strane, a ne samo "odozdo" preko bazne klase. Takodje, mozhesh bez problema da klasi promenish baznu klasu (sve dok je sintaksa poziva zadovoljena) bez kopanja po hijerarhiji. To je jako mocna stvar!
Tako neshto apsolutno nije moguce sa klasichnim (inclusive) nasledjivanjem kakvo nudi Java ili C# (ili su nudili, poshto se polako templejti uvode i u ove jezike)
Primera ovakvog dizajna ima josh dosta, recimo "policy class" dizajn.... ali to je vec druga tema.
|
|
|
|
Poslao: 28 Jan 2006 13:05
|
offline
- meka

- Počasni građanin
- Pridružio: 06 Avg 2003
- Poruke: 811
- Gde živiš: Novi Sad / Vojvodina
|
Malo offtopic, ali odakle tebi sve ove pikanterije? Hocu i ja!!!
|
|
|
|
Poslao: 28 Jan 2006 15:08
|
offline
- beli0135

- Executor
- Pridružio: 03 Jan 2005
- Poruke: 2990
- Gde živiš: Beograd
|
Pa verovatno iskustvo. Tako nesto moze se procitati u knjizi, ali implementacija i poptpuno razumevanje je nesto drugo.
|
|
|
|
Poslao: 29 Jan 2006 01:22
|
offline
- Pridružio: 19 Maj 2005
- Poruke: 352
- Gde živiš: Sabac - Novi Sad
|
beli0135 ::Pa verovatno iskustvo. Tako nesto moze se procitati u knjizi, ali implementacija i poptpuno razumevanje je nesto drugo.
Znas kako meni je ovih dana puna glava ovakvih stvari, ali realnija i bolja objasnjenja zaista nisam imao priliku da cujem, cak ni od doktora nauka...
Dopuna: 29 Jan 2006 1:22
Sad vracanje na temu...
@bNasty
Citat:Tabela virtuelnih funkcija sadrzhi nishta drugo do pointere na funkcije koje su preklopljene u toj klasi
Prvi slucaj bez virtual:
- class A{
- public:
- int k();
- int m(){k();}
- };
- class B:public A{
- public:
- int k(); //redefinisano
- };
-
- --------------------------
- main(){
- B b;
- b.m();
- // ? koje [b]k()[/b] ce se pozvati...?
- }
Drugi slucaj:
- class A{
- public:
- virtual int k();
- int m(){k();}
- };
- class B:public A{
- public:
- int k(); //redefinisano
- };
-
- --------------------------
- main(){
- B b;
- b.m();
- // ? koje [b]k()[/b] ce se pozvati...?
- }
Eee, ajde mi ispravi ako gresim, cisto hocu sebe da proverim...
Da li u prvoj varijanti zna cemu pristupa...?
-moj odgovor nema pojma (a ni ja)
-U drugoj pristupa redefinisanom k?
-Compajler je za oba k napravio v. tabele sa pokazivacima na sopstveno k.
Da li se jos nesto desi a da toga nisam ni svestan..?
P.S. Inace hvala za odgovore, mnogo mi znace....
|
|
|
|
Poslao: 29 Jan 2006 06:19
|
offline
- bNasty

- Građanin
- Pridružio: 17 Mar 2004
- Poruke: 293
- Gde živiš: UK
|
U pravu si i nisi u pravu
Kad sam prethodno pomenuo "preklopljene funkcije u tabeli virtuelnih funkcija" mislio sam na virtuelne preklopljene funkcije.
U ovom tvom primeru si dotakao neshto shto nije odmah uochljivo u C++u - tzv. "name hiding"
Evo shta se deshava (obrnutim redosledom primera)
2. U drugom primeru ce biti pozvana funkcija k() iz izvedene klase. Nema iznenadjenja, funkcija je virtuelna i kompajler ce konsultovati tabelu virtelnih funkcija i pozvati odgovarajucu funkciju u najvishoj mogucoj klasi u hijerarhiji koja definishe funkciju sa odgovarajucim potpisom (u ovom sluchaju je to k() iz izvedene klase)
1. U prvom primeru (bez virtuelnih funkcija) ne postoji nikakva tabela virtuelnih funkcija - kompajler odluchuje koju funkciju da pozove samo na osnovu scope-a u kom se trenutno nalazi kod, u ovom sluchaju pozvace k() iz bazne klase (jer pozivash funkciju preko funkcije m(), kompajler u okviru te funkcije nema pojma o izvedenoj k() funkciji).
Ovde stvari postaju intersantne - da si u istom primeru pozvao direktno k() metod bio bi pozvan metod iz izvedene klase. Zashto je ovo intersantno? Iako bi rezultat bio isti kao sa virtuelnim funkcijama razlozi su sasvim drugachije prirode - ovde u igru ulazi pomenuti "name hiding" (sakrivanje imena), osobina C++ jezika koja najcheshce unosi konfuziju i veoma chesto je kritikovana zbog toga shto nije uvek ochigledno shta ce se desiti i u kom pravcu ce se kod kretati.
Posledice se ne vide na tvom primeru, ali zamisli sledeci primer :
- class A{
- public:
- int k() {return 0;}
- int k(const char* ){return 1;}
- };
-
- class B : public A{
- public:
- int k() {return 2;}
- };
-
- // glavni kod
- B b;
-
- b.k(); // sluchaj 1
- b.k("foo"); // sluchaj 2
Shta ce se desiti u oba sluchaja, data komentarom?
Ustvari, ovakav kod se nece uopshte kompajlirati, iako to nije evidentno. Razlog je shto metod k() u izvedenoj klasi sakriva SVE istoimene metode iz bazne klase, bez obzira kakav je njihov potpis (tj. nezavisno od argumenata) - kompajler ce se u gornjem sluchaju pobuniti kako ne ochekuje funkciju k() koja ima bilo koji argument (jer B definishe samo funkciju bez argumenata - k(const char*) iz bazne klase je potpuno sakrivena).
Josh interesantnije je da isti princip vazhi i ako su funkcije virtuelne, name-hiding uvek sakriva ista imena funkcija bez obzira na tip i signature. Kompajler koristi samo one funkcije chije ime se nalazi u trenutnom scope-u! Zato iz scope-a izvedene klase ne mozhesh da vidish direktno imena funkcija u baznoj kasi, i vice-versa - scope unutrashnje(bazne) klase sakriva imena iz spoljnjeg scope-a. Samo pazi da ovo sakrivanje imena ne pomeshash sa polimorfizmom i pravilima nasledjivanja.
Nadam se samo da te nisam dodatno zbunio celom ovom prichom, ipak je 5 ujutru, vrlo je moguce da preterujem bez potrebe
|
|
|
|
Poslao: 29 Jan 2006 12:24
|
offline
- Pridružio: 19 Maj 2005
- Poruke: 352
- Gde živiš: Sabac - Novi Sad
|
Razumeo sam ovo u vezi skrivanje imena, nisam ni razmisljao ranije o tome...
Imam jos jedno pitanje...
Kad celu klasu proglasimo virtuelnom za klasu naslednicu...
- class A{
- public:
- A(){}
- void k(){cout<<"prva"<<endl;}
- void m(){k();}
- };
-
- class B:virtual public A{
- public:
- B(){}
- void k(){cout<<"druga"<<endl;}
- };
- int main()
- {
- B b;
- b.m();
- return 0;
- }
Zar ne bi trebalo da sve metode iz klase A postanu virtuelne? Kao rezultat dobijam ispis prva.
|
|
|
|