C++ bez cholesterolu: Programowanie generyczne w C++: Wprowadzenie
3.1 Programowanie generyczne - wprowadzenie
"To oczywiste, ze przekazywanie argumentow i ich interpretacja przez funkcje,
jak rowniez wywolywanie krotkiej funkcji przekazywanej przez wskaznik bedzie
stanowic duzy narzut podczas wykonywania. Dlatego nie oplaca sie tego robic.
Lepiej wziac istniejaca implementacje algorytmu i dostosowac ja do swojego
typu danych i sposobu przechowywania."
Brian Copy & Dennis Paste
Mam nadzieje oczywiscie, ze czytelnik nie potraktowal powyzszego cytatu
zbyt powaznie ;)
Programowanie generyczne jest już określeniem dość starym i właściwie należy
powiedzieć, że C++ jest nawet dość w tyle za językami, w których naturalnie
programuje się w sposób generyczny. Jednak nie jest to takie proste dla
języka, który ma być wyposażony w ścisłą typizację, zatem właściwości
pozwalające na takie programowanie wyglądają w C++ trochę nakładkowo.
Na czym to polega? Spróbujmy sobie wyobrazić funkcję, która przyjmuje dwa
argumenty i dzieli jeden przez drugi. Jest jeszcze problem zastosowanego języka
programowania. Niech by było w Haskellu, mam nadzieje, że będzie zrozumiałe:
podziel x y = x / y
I spróbujmy wywołać to w jakiś dziwaczny sposób, np.:
podziel "dwa" "trzy"
No i mamy problem. O co tu chodzi? Ano tylko i wyłącznie o to, że "dwa" i
"trzy" to nie są argumenty, które jest w stanie przyjąć operator `/'. Tak się
to właśnie odbywa w programowaniu w językach tego typu. Nie ma domyślnej
konwersji, tylko próbuje się rozpoznać typ argumentu, jaki został przekazany.
Można przekazać cokolwiek, aczkolwiek nie każde cokolwiek zostanie
zaakceptowane.
Haskell w tej kwestii jest podobny do klonów ML-a, czy też języków takich jak
Lisp, czy Prolog (a to, co go od tych języków wyraźnie odróżnia, to ścisła,
statyczna typizacja). Właśnie wzorce udostępniły językowi C++ również pewne
elementy programowania funkcjonalnego. Z owych języków jednak C++ niczego nie
przejął; z ML zostały wzięte częściowo wyjątki, natomiast wzorce i
przestrzenie nazw pochodzą z Ady.
W C++ deklaracja owego podziel brzmiałaby:
template <typename T>
T podziel( T x, T y )
{ return x/y; }
Jak widać, składnia jest o wiele dłuższa, ale za to nie tracimy ani typizacji,
ani domyślnych konwersji. Do tej funkcji `podziel' akurat należy podać
argumenty tego samego typu, a zwraca się też argument tego typu. Można
oczywiście zadeklarować więcej typów, aczkolwiek trudno jednak stwierdzić,
jaki typ następnie miałby być zwracany (C++ niestety nie posiada mechanizmów
domniemania typu zwracanego i jest to od pewnego czasu znany problem). Zatem w
powyższym przykładzie można to wywołać jako
podziel( 10, 2 ), czy podziel( 23.54, 5.0 ), ale niestety
podziel( 2, 2.5 ) już nie przejdzie.
Programowanie generyczne za pomocą wzorców jest trudniejsze i bardziej
uciążliwe od pisania generycznego w meta-językach. Daje jednak większe i
ciekawsze możliwości, nie wspominając już o szybkości, zwłaszcza że nie tylko
typ może być na liście parametrów, ale można je też specyfikować wprost lub
częściowo.
Jeszcze parę słów o wzorcach. Same wzorce w C++ też nie wzięły się z
powietrza. Są one konsekwencją tego, co już zostało zapoczątkowane wcześniej w
języku C (podobnie jak z referencjami). W języku C od zawsze mieliśmy tablice
i wskaźniki, które były właśnie takimi meta-typami. Miały swoje właściwości,
ale wskaźnik jako-taki sam nigdy nie był typem. Podobnie z tablicą. Ma ona
swoje właściwości, operator indeksowania, swój rozmiar itd., aczkolwiek
rozmiar tablicy jest zależny np. od rozmiaru elementów. Zatem tablica, jak też
wskaźnik były w C właśnie takimi swoistego rodzaju wzorcami, które miały tylko
odpowiednie wsparcie składniowe. W C++ rozwinięto ten pomysł, pozwalając
użytkownikowi tworzyć samemu takie meta-typy.
Wyszukiwarka
Podobne podstrony:
introGRADIENT INTROIntrointroIntro (40)Appendices01 Introtcpip introintro1 Intro4 Intro to lg morph LECTURE2014intro 2social?onomy introMR 362 ESPACE INTRO33 ENVI Zoom IntroINTRO00 INTROmacierze introwięcej podobnych podstron