PDA

Pogledaj cijelu verziju : c++ polimorfizam



kvecoman
14-02-2009, 07:30
Trebao ih nekakvo objašnjenje ili link na neki članak koji objašnjava polimorfizam, virtualne funkcije koje idu uz to itd. Jednostavno mi to nikako ne ide u glavu pa se :pray: bilo kome ko zna nešto. Unaprijed Hvala. :cry:

eddie2142
14-02-2009, 10:02
najbolji nacin da naucis nesto takvo je uporno citati ili naci nekoga tko to razumije pa da te poucava, ali u RL
a ima jos jedan nacin, kupi knjigu i citaj dok ti nebude jasno

SkunK
14-02-2009, 10:14
najbolji nacin da naucis nesto takvo je uporno citati ili naci nekoga tko to razumije pa da te poucava, ali u RL
a ima jos jedan nacin, kupi knjigu i citaj dok ti nebude jasno

Ako ga zanima polimorfizam u C++ i isključivo samo on, zar bi trebao pročitati ostatak knjige koji ne govori o polimorfizmu? Dao si mu onaj univerzalni pomalo u ovom slučaju - glupi odgovor koji je sam ponavaljanje jedne te iste stvari.

Da je pitao : "kako da napravim igru ", "kako da naučim c++?" onda bi mu mogao reći da kupi knjigu i počme učiti...ovako, ne jer ga zanima specifični dio.

@kvecoman

http://www.cplusplus.com/doc/tutorial/polymorphism.html

http://www.cs.bu.edu/teaching/cpp/polymorphism/intro/

http://www.programmers-corner.com/tutorial/36


VIDEO : http://www.slideshare.net/reachanil/sta ... phism-in-c (http://www.slideshare.net/reachanil/static-and-dynamic-polymorphism-in-c)

kvecoman
14-02-2009, 11:11
Puno hvala Reiko, ovo će mi veoma pomoći :bravo:

Luka
14-02-2009, 11:53
Ukratko, polimorfizam je svojstvo OOP-a koje omogućuje da se, u nekoj hijerarhiji klasa, objektu niže klase (izvedene) pristupa kao objekti više klase (neke od osnovnih klasa). Pod "pristupa" mislim na sučelje klase. Polimorfizam ima smisla tek kad se radi sa pokazivačima i referencama jer su to situacije kada je pravi tip klase ne poznat..

Npr. imaš klasu vizualni_objekt sa metodom nacrtaj() (nacrtaj je "čista" virtualna funkcija). Radiš program za vektorsko crtanje, i u njemu se nalazi lista pokazivača na objekt vizualni_objekt. Svaki oblik koji se može nacrtati u tvojem programu je izveden od te klase. Npr. "class pravokutnik : public vizualni_objekt...". Svaki od tih oblika (koji su ustvari izvedene klase) ima vlastitu definiciju funkcije nacrtaj, jer vizualni_objekt ne može znati kako će crtati svi mogući oblici.
Kada se nešto nacrta u tvom programu (npr. pravokutnik), dodaješ ga u listu pokazivača na vizualne objekte, npr. ovom naredbom "moji_objekti.push_back(&moj_novostvoreni_pravokutnik);" (premda je bolja ideja dinamički alocirati taj novi pravokutnik da ne bi bilo visećih pokazivača).
Da nema polimorfizma, sad se postavlja pitanje kako ćeš pristupati tim objektima, ako neznaš njihove tipove već samo osnovni tip (vizualni_objekt). No, polimorfizam to rješava virtualnim funkcijama - metodama. Na početku sam spomenuo virtualnu funkciju nacrtaj() - svaka izvedena klasa ju moraSimati vlastitu definiciju te funkcije, u suprotnom se neće moći koristiti (izravno, ali će se i dalje moći iz nje izvesti novi tipovi). Kada se pozove moji_objekti[index]->crtaj(), pozvati će se ustvari crtaj() definiran u izvedenoj klasi (mehanizam koji sve to pamti su virtualne tablice, ali to nije tako bitno...).
Koja je svrha polimorfizma?
Da ga nema, način na koji bi se rješavao problem bi bio da se u svakoj osnovnoj klasi doda varijabla nekog tipa (npr. enum) koja će govoriti o kojem se izvedenom tipu radi. Nakon toga bi crtaj() switch-em određivao koju će metodu pozvati. To se kosi sa svima načelima OOP-a jer osnovna klasa u ovom slučaju mora znati što će se od nje raditi, kao i njihovu implementaciju.
Još jedan način bi bio dodati pokazivač na izvedenu funkciju, što je nešto elegantnije rješenje od prethodnog, no i dalje je naporno to stalno raditi.

Tracer
14-02-2009, 11:58
Izvedene klase uvijek se mogu predstaviti i klasom roditelja tj. pretvorbom na više. Primjerice, recimo da imamo klase Pas i Mačka. One bi se mogle predstaviti jednom klasom, a nju bi mogli nazvati Zivotinja, što naravno podrazumijeva da su klase Pas i Mačka derivacije te klase.

Takvu pretvorbu radimo na način da pokazivač bazne klase adresiramo na objekt izvedene klase. U tom slučaju pristup funkcijama članicama će se isključivo odnositi na funkcije članice bazne klase bez obzira što je pokazivač bazne klase adresiran na objekt derivacije klase. Da bi to izbjegli koristimo
virtualne funkcije. Npr.:


#include <iostream.h>

class Zivotinja{
public:
virtual void Vrsta(){}
};
class Pas : public Zivotinja{
public:
void Vrsta(){
cout << "Pas\n";
}
};
class Macka : public Zivotinja{
public:
void Vrsta(){
cout << "Macka\n";
}
};
int main(){
Pas Rex;
Macka Mac;
Zivotinja *Ziv;

Ziv = &Rex;
Ziv->Vrsta(); // Pas
Ziv = &Mac;
Ziv->Vrsta(); // Macka
return 0;
}

Također, treba pripaziti i kada je riječ o destruktoru derivirane klase, a pogotovo ako on vrši dealokaciju memorije jer tada i destruktor bazne klase OBAVEZNO mora biti virtualan jer bi u protivnom derivirana klasa napravila memory leak:


class Bazna{
public:
virtual ~Bazna(){
cout << "Destruktor bazne klase...\n";
}
};
class Derivacija : public Bazna{
private:
int* polje;
public:
Derivacija(int n){
polje = new int[n];
}
~Derivacija(){
delete[]Spolje;
cout << "Polje je dealocirano! (destruktor derivacije...)\n";
}
};

i pretvorba:


Bazna* X = new Derivacija(10);
delete X; // poziva oba destruktora a ne samo jedan!

Osim u ovim slučajevima ključna riječ virtual se nalazi i kod virtualnog nasljeđivanja kod situacije kada dvije derivacije iste bazne klase kreiraju novi objekt koji nastaje nasljeđivanjem od njih dvije. Tada se javlja sukob među tim pod-objektima tih dviju derivacija:


#include <iostream.h>

class Boja{
public:
virtual void naziv() = 0;
};
class Bijela : virtual public Boja{
public:
void naziv(){
cout << "Bijela";
}
};
class Crna : virtual public Boja{
public:
void naziv(){
cout << "Crna";
}
};
class Siva : public Bijela, public Crna{
public:
void naziv(){
// biramo funkciju iz nekog pod-objekta
Bijela::naziv();
Crna::naziv();
}
};
int main()
{
Boja* pBoja = new Siva;
pBoja->naziv();
delete pBoja;
return 0;
}

Uglavnom, tu su ti primjeri pa malo prostudiraj. Ako bude što nejasno, pitaj.

SkunK
14-02-2009, 13:07
Puno hvala Reiko, ovo će mi veoma pomoći :bravo:

No biggy :)

No slušaj Tracera, čovjek je znanje u biološkom obliku :D

kvecoman
15-02-2009, 07:48
Ok, evo bio sam jučer pregledavao vaše primjere i nešto teorije pa sam onda sam probao napisati primjer polimorfizma i nadam se da sam uspio.



#include <iostream>

using namespace std;

class CD
{
public:
virtual void Info()
{
cout << "CD: 700MB" << endl;
}
};

class DVD : public CD
{
public:
void Info()
{
cout << "DVD: 4.7 GB" << endl;
}
};

class DVD9 : public CD
{
public:
void Info()
{
cout << "DVD9: 9.4 GB" << endl;
}
};

int main()
{
cout << "Stvaram objekte izvedenih klasa\n" << endl;
DVD d;
DVD9 pcplay;

cout << "Onda pokrećem Info() funkciju izvedenih klasa" << endl;
d.Info();
pcplay.Info();


cout << "\n\nSada stvaram pokazivač CD c koji pokazuje na DVD d i pozivam c.Info()" << endl;
CD *c = &d;
c->Info();

cout << "\n\nSada taj pokazivač usmjerujem da pokazuje na DVD9 pcplay i pozivam c.Info()" << endl;
c = &pcplay;
c->Info();

//Ovaj dio je samo da mi zadrži prozor
int x;
cin>>x;
return 0;
}

Eto, mislim da bi to moglo biti to :roll:

Luka
15-02-2009, 14:36
Da, to je to :)