Morfidon napisał(a):Zeman napisał(a):Faktycznie, wg definicji wikipedii samo juz dziedziczenie jest polimorfizmem, tzn wystarczy zwykle przypisanie instancji potomka do zmiennej rodzica i juz.
Dziedziczenie to nie przypisanie instancji potomka do zmiennej rodzica.
No tak, to wiadomo ze nie to samo.
Morfidon napisał(a):
Zeman napisał(a):Code: Zaznacz cały
char *a; // <- wskaznik na a
byte *b; // <- wskaznik na b
...
b = a; // a i b wskazuja na ten sam bajt
Nie ma czegoś takiego jak wskaźnik "na a". Zapis char *a; oznacza: stwórz zmienną o nazwie "a" i zarezerwuj dla niej miejsce w pamięci. Wartość jaką może przechowywać ta zmienna to adres zmiennej typu char
Może to trochę nie na temat, ale wolałem poprawić, aby nie było nieścisłości
No tak, powinno byc samo "wskaznik" albo "wskaznik na zmienna typu char / byte", przejezyczenie, ale podejrzewam ze wiadomo o co mi chodzi.. Przyklad pokazuje sytuacje, ze zmienne a i b wskazuja na te sama komorke w pamieci, czyli odnosza sie do tej samej wartosci tylko z innym potraktowaniem w sensie typu. Teraz wg wikipedii moim zdaniem to sie tez zalicza do polimorfizmu
http://pl.wikipedia.org/wiki/Polimorfiz ... rzutowanie
cytat z Wikipedii napisał(a):Wszelkiego rodzaju zmiany typów, zarówno jawne jak i niejawne, statyczne i dynamiczne, również należy uznać za mechanizmy polimorficzne, gdyż pozwalają traktować wartości i zmienne jednego typu, tak jakby były wartościami innego typu.
Morfidon napisał(a):
Zeman napisał(a):dla odmiany jakis tam pierwszy lepszy wyklad wygooglany utozsamia polimorfizm z wirtualnoscia metod
Bo to jest najlepszy przykład tak jak i np. overloading funkcji: na podstawie przysłanych argumentów kompilator
SAM decyduje co ma zrobić

Najważniejsze zdanie dotyczące polimorfizmu to
Istotą polimorfizmu jest to aby to system decydował o szczegółach, nie programista. Przez system należy tu rozumieć kompilator i system czasu wykonania.
Jeszcze raz - pod wskazanym linkiem mozna przeczytac:
cytat z linka z wykladem napisał(a):
Dla znających Pythona czy Javę może to być zaskoczenie. Tam bowiem, jak w większości języków obiektowych, decyduje typ dynamiczny: jeśli obiekt, na rzecz którego wywołujemy metodę, jest klasy pochodnej względem tej, która jest typem statycznym wskaźnika (odniesienia) do tego obiektu, to wywołana będzie wersja tej metody pochodząca z klasy pochodnej (jeśli została tam przedefiniowana). Mówimy wtedy, że metody są wirtualne. A zatem w Javie wszystkie metody (prócz finalnych i prywatnych) są wirtualne. Klasy w których istnieją metody wirtualne, nazywamy klasami polimorficznymi, bo wywołanie ich poprzez wskaźnik (odniesienie) pewnego typu zależy od typu obiektu na który ten wskaźnik wskazuje, ma zatem „wiele kształtów”. A zatem w Javie klasy, prócz finalnych, są polimorficzne.
Trzeba jednak zdawać sobie sprawę, że ceną za polimorfizm jest pewna utrata wydajności. Dla wywołań na rzecz obiektów klas niepolimorficznych odpowiednia metoda jest wybierana już w czasie kompilacji na podstawie typu statycznego. Mówimy, że następuje wtedy wczesne wiązanie (ang. early binding).
Typ dynamiczny obiektu wskazywanego przez wskaźnik lub odniesienie może być natomiast określony dopiero w czasie wykonania. Kompilator, napotkawszy wywołanie metody z klasy polimorficznej, nie może umieścić w pliku wykonywalnym kodu odpowiadającego wywołaniu konkretnej funkcji. Zamiast tego umieszczany jest tam kod sprawdzający prawdziwy typ obiektu i wybierający odpowiednią metodę. Mówimy, że następuje wtedy późne wiązanie (ang. late binding). Tak więc każde wywołanie metody wirtualnej powoduje narzut czasowy w trakcie wykonania. Wybranie odpowiedniej metody wymaga też dostępu do informacji o różnych wersjach metody w klasach dziedziczących. Informacja ta jest zwykle umieszczana w specjalnej tablicy, której adres jest przechowywany w każdym obiekcie klasy polimorficznej. Obiekt taki musi być zatem większy niż obiekt analogicznej klasy niepolimorficznej - polimorfizm powoduje zatem również narzut pamięciowy.
W C++, przede wszystkim właśnie ze względu na wydajność, podejście do polimorfizmu jest nieco inne niż w większości innych języków obiektowych. Jako programiści mamy mianowicie możliwość wyboru: czy chcemy, aby definiowana klasa była polimorficzna, czy też z polimorfizmu rezygnujemy na rzecz podniesienia wydajności. Domyślnie nowo definiowane klasy nie są polimorficzne, a zatem definiowane w nich metody nie są wirtualne. Jeśli w programie następuje wywołanie, poprzez wskaźnik lub odniesienie, dowolnej metody na rzecz obiektu klasy niepolimorficznej, kompilator umieszcza od razu wywołanie konkretnej metody w kodzie wynikowym. Kieruje się przy tym wyłącznie typem zadeklarowanym (statycznym) wskaźnika lub odniesienia.
Aby definiowana klasa była polimorficzna, wystarczy jeśli choć jedna metoda tej klasy będzie wirtualna. W szczególności może to być destruktor (ale nie konstruktor - ten wirtualny nie może być nigdy).
Zaznaczylem czerwonym fragmenty swiadczace o tym, ze klasa bez metod wirtualnych nie jest polimorficzna - jest to napisane wprost. Jest tez mowa o poznym wiazaniu i tablicy VMT, o tym, ze w C++ mamy do wyboru czy chcemy wydajnosc czy polimorfizm.
Code: Zaznacz cały
class A {
public test() { wypiszNaEkran("Jestem z A"); }
}
class B : A {
new public test() { wypiszNaEkran("Jestem z B"); }
}
...
A zmienna = new B();
zmienna.test(); // wypisze Jestem z A, bo metoda nie jest wirtualna, a typ zmiennej to A (wczesne wiazanie)
((B)zmienna).test(); // wypisze Jestem z B, bo my jawnie wymusilismy to na kompilatorze, typ znany podczas kompilacji (wczesne wiazanie) i nie ma zagladania do VMT
(nie kompilowalem powyzszego, wiec moze byc literowka, ale mam nadzieje ze zamysl jest jasny)
teraz wg wiki jest to polimorfizm a wg wykladu obie klasy nie sa polimorficzne.
Szczerze mowiac to takie troche sprzeczne, bo niby stosujemy polimorfizm stosujac klase nie polimorficzna. Jedyne wytlumaczenie jest takie, ze mozna stosowac polimorfizm recznie poza klasa nawet na klasie ktora nie jest polimorficzna, czyli programista jawnie rzutuje, ale to wszystko powoduje ustalenie metody na poziomie kompilacji i nie ma poznych wiazan. Szczerze mowiac troche zglupialem juz teraz. Tylko wtedy po co klasa sie nazywa nie polimorficzna
Morfidon napisał(a):
oraz fakt, że jedna nazwa(morph) może znaczyć tak wiele (poli).
[/quote]
ciezko tu mowic o jednej nazwie bo niby faktycznie ta sama nazwa ale jedna bez rzutowania a druga polaczona z rzutowaniem, czyli taka srednio ta sama.
W Delphi mozna bylo nawet wymusic rzutowanie na niezgodny typ:
Code: Zaznacz cały
(z pamieci)
A = class
procedure Test;
end;
B = class
procedure Test;
end;
...
var c: A;
c:= B(A.Create);
// a jak powyzsze nie przejdzie to zastosowac jeszcze rzutowanie na pointer, bo nie pamietam czy to przejdzie
c.Test;
i teraz uwaga - B nie dziedziczy po A. Powyzsze przejdzie, bo A i B maja tego samego przodka TObject i metoda A.Test bedzie miala ten sam offset wzgledem klasy co B.Test bo sie skompiluje tak samo - jako pierwsza metoda w klasie

(pomijam juz oczywistosc ze tak sie nie robi)
Niby tez nazwa taka sama ale tez jak sie uprzemy mozemy zrzutowac. no i teraz wg wiki rzutowalismy a skoro tak to jest to polimorfizm
Ba, nawet nazwa nie musi byc ta sama:
Code: Zaznacz cały
A = class
procedure TestAAA;
end;
B = class
procedure TestBBB;
end;
...
var c: A;
c:= B(A.Create);
// a jak powyzsze nie przejdzie to zastosowac jeszcze rzutowanie na pointer, bo nie pamietam czy to przejdzie
c.TestAAA;
No i stworzylismy instancje B a zrzutowalismy na cos calkiem innego - na A i jeszcze metoda jest inna.
Pozdrawiam