LEKCJA29.TXT

(9 KB) Pobierz
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);   
}  
 
...
Zgłoś jeśli naruszono regulamin