LEKCJA 29: FUNKCJE I OVERLOADING. ________________________________________________________________ W trakcie tej lekcji dowiesz si�, jak jeszcze w C++ mo�na wykorzystywa� funkcje. ________________________________________________________________ w C++ jedna funkcja mo�e by� definiowana wielokrotnie a ka�da z wersji funkcji mo�e by� przystosowana do obs�ugi innego typu argument�w. C++ wybiera t� w�a�ciw� wersj� funkcji automatycznie. JEDNA NAZWA FUNKCJI - WIELE ZASTOSOWA�. Overloading funkcji bywa czasem w podr�cznikach dzielony na odr�bne zagadnienia: * funkcja mo�e tolerowa� r�n� liczb� argument�w (co da�o si� spokojnie realizowa� r�wnie� w klasycznym C - vide printf()); * funkcja mo�e tolerowa� r�ne typy argument�w; * funkcja mo�e realizowa� r�ne operacje dla r�nych Wyobra�my sobie, �e mamy funkcj� wydrukuj(), kt�ra potrafi wys�a� na ekran otrzymany znak: void wydrukuj(char znak) { cout << znak; } Tak zdefiniowan� funkcj� mo�emy wywo�a� w programie w nast�puj�cy spos�b: wydrukuj('Z'); Czasem jednak wygodniej by�oby, gdyby nasza funkcja by�a bardziej elastyczna i pozwala�a na wykonanie szerszego zakresu operacji, np.: wydrukuj('Z'); wydrukuj(75); // 75 to kod ASCII znaku, zamiast znaku bezpo�r. wydrukuj("Wiecej niz znak - tekst"); W klasycznym j�zyku C wymaga to zdefiniowania nowej funkcji, natomiast w C++ to, �e funkcja wydrukuj() zosta�a ju� zdefiniowana w niczym nie przeszkadza. Poni�ej definjujemy tak� funkcj�. ... class KLASA { public: void wydrukuj(char znak); void wydrukuj(int kod_ASCII); void wydrukuj(char *string); //wska�nik do lancucha } �a�cuch znak�w jest widziany jako jednowymiarowa tablica zawieraj�ca dane typu znakowego, czyli w taki spos�b: char TABLICA[9] ={ "123456789" }; Definice powinny mie� nast�puj�c� posta�: void KLASA::wydrukuj(char znak) {cout << znak;}; void KLASA::wydrukuj(int kodASCII) {cout << (char) kodASCII;}; void KLASA::wydrukuj(char *string) {cout << string;}; Zapis: cout << (char) kodASCII; oznacza forsowanie typu - zamie� typ int na typ char - przyporz�dkowanie kodowi ASCII - znaku. Wywo�anie tej funkcji w programie mo�e spowodowa� r�ne dzia�anie, w zale�no�ci od typu i ilo�ci argument�w, z kt�rym(i) funkcja zostaje wywo�ana. Wywo�ania funkcji mog� wygl�da� np. tak: KLASA Obiekt1, Obiekt2; main() { ... Obiekt1.wydrukuj('A'); //Wydrukuje si� litera A Obiekt1.wydrukuj(99); //Wydrukuje si� litera c Obiekt2.wydrukuj("napis"); //Wydrukuje si� napis. ... } Taki spos�b post�powania umo�liwia funkcjom wi�ksz� elastyczno�� i pozwala operowa� bez konflikt�w na r�nych rodzajach danych. J�zyk C posiada funkcje s�u��ce do kopiowania �a�cuch�w znakowych: strcpy() i strncpy(). Funkcja biblioteczna strncpy() przerywa proces kopiowania po zako�czeniu �a�cucha �r�d�owego, b�d� po skopiowaniu zadanej ilo�ci znak�w. Dzi�ki mechanizmowi overloadingu mo�emy utworzy� nasz� w�asn� funkcj� kopiuj_string(), kt�ra zale�nie od sytuacji zadzia�a jak strcpy(), b�d� tak jak strncpy(). [P104.CPP] # include <iostream.h> /* dwa porototypy - dwie wersje funkcji kopiuj_string() */ /* source: destination: len: */ void kopiuj_string(char*, const char*); //Dwa argumenty void kopiuj_string(char*, const char*, int); //a tu trzy static char Piggie[20], Kermit[32]; main() { kopiuj_string(Piggie, "Panna Piggie"); kopiuj_string(Kermit, "Kermit - to protokul transmisji", 6); cout << Kermit << " oraz " << Piggie; return 0; } void kopiuj_string(char *destin, const char *source) { while((*destin++ = *source++) != '\0') /* instr. pusta */ ; } void kopiuj_string(char *destin, const char *source, int len) { while (len && (*destin++ = *source++) != '\0') --len; while (len--) *destin++ = '\0'; } [S] Source- Destination. ________________________________________________________________ source - tu: �r�d�owy �a�cuch znak�w. Og�lnie - �r�d�o. Typowy skr�t src. destin - tu: �a�cuch przeznaczenia. Og�lnie destination - miejsce przeznaczenia. Typowy skr�t dest, dst, destin. len - tu: d�ugo��. ________________________________________________________________ O FUNKCJACH WPLECIONYCH - TYPU inline. Czsami zale�y nam na przyspieszeniu dzia�ania programu obiektowego (zwykle kosztem zwi�kszenia d�ugo�ci pliku). Je�li w �r�d�owym tek�cie programu nast�puje wywo�anie funkcji typu inline, to kompilator wstawia w to miejsce ca�e cia�o funkcji (funkcje typu inline nie maj� bezpo�redniego ani wy��cznego odniesienia do obiektowego stylu programowania). Dla przyk�adu, je�li nadaliby�my naszej funkcji wydrukuj() status funkcji inline, to fragment programu: obiekt.wydrukuj(65); //Kod ASCII zosta�by zast�piony wstawionym w to miejsce cia�em funkcji wydrukuj(): .... cout << (char) 65; .... Jest to skuteczna metoda przyspieszenia dzia�ania program�w. Je�li chcemy zastosowa� technik� funkcji inline w stosunku do metod nale��cych do danej klasy, powinni�my u�y� s�owa kluczowego "inline" w definicjach funkcji. Zwr�� uwg�, �e w samej definicji klasy s�owo inline NIE POJAWIA SI�: [P105.CPP] # include <iostream.h> class Klasa { public: void wydrukuj(char* tekst); void wydrukuj(char Znak); void wydrukuj(int KodASCII); }; inline void Klasa::wydrukuj(char* tekst) { cout << tekst; } inline void Klasa::wydrukuj(char Znak) { cout << Znak; } inline void Klasa::wydrukuj(int KodASCII) { cout << (char) KodASCII; } void main() { Klasa Obiekt; cout << "Obiekt wyprowadza dane: " << '\n'; Obiekt.wydrukuj(65); Obiekt.wydrukuj('B'); Obiekt.wydrukuj("C i juz"); } Wszystkie wersje funkcji wydrukuj() otrzyma�y status inline. Oznacza to, �e funkcje te nie b�d� w programie wywo�ywane lecz ca�e cia�a funkcji zostan� wstawione do programu w miejsca wywo�a�. Jest to mechanizm podobny do wstawiania do programu makrorozkaz�w z t� r�nic�, �e w przypadku funkcji inline C++ przeprowadza dodatkowo sprawdzenie zgodno�ci typ�w argument�w (ang. type checking). W naszym przypadku kompilator C++ wstawi do programu cia�o funkcji tyle razy, ile razy funkcja powinna zosta� wywo�ywana. Zastosowanie funkcji inline jest op�acalne, je�eli cia�o funkcji jest stosunkowo kr�tkie. [!!!] A CZY NIE MO�NA WEWN�TRZ KLASY ? ________________________________________________________________ Mo�na. Je�li umie�cimy pe�n� definicj� funkcji wewn�trz definicji klasy, to taka funkcja staje si� AUTOMATYCZNIE funkcj� typu inline. ________________________________________________________________ Status inline mo�emy nada� wszystkim trzem wersjom funkcji wydrukuj() umieszczaj�c definicje funkcji bezpo�rednio wewn�trz definicji klasy: class Klasa { public: inline void wydrukuj(char* a) { cout << a; } inline void wydrukuj(char z) { cout << z; } inline void wydrukuj(int kod) { cout << (char) kod; } }; W wi�kszo�ci przypadk�w daje to efekt pozytywny. Je�li definiujemy funkcje wewn�trz klasy, s� to zwykle funkcje o kr�tkim ciele. OVERLOADING KONSTRUKTOR�W. W C++ mo�emy podda� overloadingowi tak�e konstruktory. UWAGA: destruktor�w nie mo�na podda� overloadingowi. Overloading konstruktor�w nie wyr�nia si� niczym specjalnym. Wyobra�my sobie, �e tworzymy obiekt klasy Klasa o nazwie Obiekt. Je�li chcemy, by konstruktor przy zak�adaniu Obiektu przekaza� mu �a�cuch znak�w "zzzz", mo�emy to zrobi� na dwa sposoby. Raz polecimy konstruktorowi przekaza� do obiektu �a�cuch znak�w "zzzz", a za drugim razem polecimy przekaza� do obiektu czterokrotnie znak 'z': Obiekt("zzzz"); /* albo */ Obiekt('z', 4); Je�li w programie zadeklarujemy obiekt danej klasy, spowoduje to automatyczne wywo�anie konstruktora z parametrem podanym w momencie deklaracji obiektu. class Klasa { public: Klasa(char*); Klasa(char, int); }; Wersje konstruktora Klasa::Klasa() powinni�my zdefiniowa� tak: Klasa::Klasa(char *tekst) { cout << tekst; } Klasa::Klasa(char Znak, ile = 4); { for(int i = 1; i < ile; i++) cout << Znak; } Dodajmy jeszcze jeden kontruktor domy�lny. Konstruktory domy�lne dzia�aj� wed�ug zasady, kt�r� w naturalnym j�zyku da�oby si� przekaza� mniej wi�cej tak: "dop�ki nie zdecydowano inaczej...". Dop�ki nie zdecydowano inaczej - obiekt otrzyma znak 'x'. class Klasa { public: Klasa(); Klasa(char*); Klasa(char, int); }; ... Klasa::Klasa(void) { cout << 'x'; } Praktyczne zastosowanie w programie b�dzie wygl�da� tak: [P106.CPP] # include <iostream.h> class Klasa { public: Klasa(); Klasa(char*); Klasa(char, int); }; Klasa::Klasa(void) { cout << 'x'; } Klasa::Klasa(char *tekst) { cout << tekst; } Klasa::Klasa(char Znak, int ile = 4) { for(int i = 0; i < ile; i++) cout << Znak; } static char *p = "\nJestem Obiekt."; void main() { Klasa Obiekt1; //Konstr. domy�lny Klasa Obiekt2('A'); // ile - domyslnie == 4 Klasa Obiekt3('B', 3); Klasa Obiekt4(p); }
ZAZZY