LEKCJA30.TXT

(16 KB) Pobierz
LEKCJA 30: WYMIANA DANYCH MI�DZY OBIEKTAMI.  
________________________________________________________________ 
 
W trakcie tej lekcji dowiesz si�, jak mo�na wymienia� dane i  
informacje pomi�dzy r�nymi obiektami.  
________________________________________________________________ 
 
 
Hermetyzacja danych jest cenn� zdobycz�, ale od czasu do czasu  
obiekty powinny dokonywa� pomi�dzy sob� wymiany informacji,  
tak�e tych wewn�trznych - prywatnych. Ten problem mo�e sprawia�  
programi�cie troch� k�opot�w - nale�y zatem po�wi�ci� mu troch�  
uwagi.  
 
DOST�P DO DANYCH PRZY POMOCY FUNKCJI KATEGORII friend.  
 
Aby wyja�ni� mechanizmy dost�pu do danych obiekt�w b�dziemy  
potrzebowa�:  
 
* wielu obiekt�w;  
* danych prywatnych obiekt�w (dost�p do publicznych,  
"niezakapsu�kowanych" danych jest prosty i oczywisty);  
* funkcji o specjalnych uprawnieniach. 
 
Takie funkcje o specjalnych uprawnieniach - z mo�liwo�ci�  
odwo�ywania si� do prywatnych danych wielu obiekt�w (a nie tylko 
 
swojego) musz� w C++ posiada� status "friend" (ang. friend -  
przyjaciel).  
 
Nasz przyk�adowy program b�dzie operowa� tablic� z�o�on� z  
obiekt�w klasy Licznik.  
 
class Licznik 
{  
  char moja_litera;  
  int ile; 
public:  
  void Inicjuj_licznik(char);  
  void Skok_licznika(void);  
  void Pokazuj(); 
};  
 
 ...  
Licznik TAB[MAX]; 
 
Obiekty - liczniki b�d� zlicza� wyst�pienie (ka�dy swojego)  
okre�lonego znaku w strumieniu znak�w wej�ciowych (wczytywanym z 
 
klawiatury). Tablica b�dzie si� sk�ada� z MAX == 26 element�w -  
obiekt�w - licznik�w, po jednym dla ka�dej du�ej litery  
alfabetu. Tablica b�dzie nazywa� si� TAB[26]. Po zadeklarowaniu: 
 
 
nazwa_klasy TAB[MAX];  
 
kolejne obiekty b�d� si� nazywa�:  
 
nazwa_klasy Obiekt1 == TAB[0];       //Licznik 1 - 'A' 
nazwa_klasy Obiekt2 == TAB[1];       //Licznik 2 - 'B' 
 ...                                    ... 
nazwa_klasy ObiektN == TAB[N-1];  
 
Po wprowadzeniu znaku z klawiatury wywo�amy wbudowan� do ka�dego 
 
obiektu funkcj� Skok_licznika(), kt�ra doda jedynk� do  
wewn�trznego licznika obiektu. Wywo�uj�c funkcj� zastosujemy  
zamiast typowej sk�adni  
 
ObiektK.Skok_licznika();  
 
odpowiadaj�c� jej w tym wypadku notacj�  
 
TAB[i].Skok_licznika(); 
 
Powinni�my jeszcze przed wywo�aniem funkcji sprawdzi�, czy znak  
jest du�� liter� alfabetu. W przyk�adowym programie zrobimy to  
tak:  
 
 ... 
  cin >> znak;                     //Pobranie znaku z klawiatury 
  for(int i = 0; i < 26; i++) 
     {  
       if(i == (znak - 'A')) TAB[i].Skok_licznika();  
     } 
 ... 
 
Dzi�ki temu wewn�trzny licznik obiektu TAB[2] zostanie  
powi�kszony tylko wtedy, gdy znak - 'A' == 2 (znak jest liter�  
C, bo 'C' - 'A' == 2).  
 
Mo�na to zapisa� skuteczniej. 
... 
   cin >> znak; 
   TAB[znak - 'A'].Skok_licznika();    //Inkrementacja licznika  
 ... 
 
b�d� jeszcze kr�cej:  
 
 ... 
   TAB[getch() - 'A'].Skok_licznika();  
 ... 
 
Istnieje tu wszak�e niebezpiecze�stwo pr�by odwo�ania si� do  
nieistniej�cego elementu tablicy, przed czym powinni�my si�  
wystrzega�. 
 
W wyniku dzia�ania programu otrzymamy zliczon� ilo��  
wyst�powania danej litery w strumieniu znak�w wej�ciowych.  
 
[P107.CPP]  
  
# include <ctype.h>            //prototyp toupper()  
# include <iostream.h>   
  
class Licznik  
{   
  char moja_litera;   
  int ile;  
public:   
  void Inicjuj(char);   
  void Skok_licznika();   
  void Pokazuj();  
};   
  
void Licznik::Inicjuj(char z)   
{   
  moja_litera = z;   
  ile = 0;   
}   
  
void Licznik::Skok_licznika(void)   
{   
  ile++;   
}   
  
void Licznik::Pokazuj(void)   
{   
  cout << "Znak " << moja_litera << " wystapil "   
       << ile << " razy" << '\n';   
}  
main()   
{   
const MAX = 26; 
Licznik TAB[MAX];   
register int i;   
  
/* inicjujemy liczniki:  -------------------------------*/   
  
for(i = 0; i < MAX; i++)   
   {   
     TAB[i].Inicjuj('A' + i);   
   }  
/* pracujemy - zliczamy: -------------------------------*/  
  
cout << "Wpisz ciag zankow zakonczony kropka [.]" << '\n';  
for(;;)   
  { char znak;  
    cin >> znak;  
    if(znak == '.') break;  
    for(i = 0; i < MAX; i++)   
       {   
         if(i == (znak - 'A')) TAB[i].Skok_licznika();   
       }   
  }  
/* sprawdzamy: ----------------------------------------*/  
  
char sprawdzamy;  
cout << '\n' << "Podaj znak do sprawdzenia: " << '\n';   
cin >> sprawdzamy;  
cout << "Wyswietlam wyniki zliczania: \n";   
  TAB[toupper(sprawdzamy) - 'A'].Pokazuj();   
  
return 0;   
}  
  
Je�li chcieliby�my zliczy� ilo�� wszystkich wprowadzonych  
znak�w, powinni�my zsumowa� dane pobrane od wielu obiekt�w.  
 
Je�li dane przechowywane w obiektach maj� status danych  
prywatnych, to dost�p do tych danych mo�e by� utrudniony. Do  
tego momentu dost�p do danych prywatnych obiektu mogli�my  
uzyska� tylko pos�uguj�c si� autoryzowan� do tego metod� -  
w�asn� funkcj� wewn�trzn� tego� obiektu. Ale wtedy nie mieli�my  
dost�pu do danych innych obiekt�w a tylko do jednego -  
"w�asnego" obiektu funkcji. Je�li zatem chcieliby�my zsumowa�  
zawarto�ci wielu obiekt�w - licznik�w, to nale�y do tego  
zastosowa� tzw. funkcj� "zaprzyja�nion�" - friend function.  
Je�li deklaruj�c funkcj� zastosujemy s�owo kluczowe friend, to  
taka zaprzyja�niona z klas� funkcja uzyska prawo dost�pu do  
prywatnych element�w danej klasy. Zadeklarujemy tak� przyk�adow� 
 
zaprzyja�nion� funkcj� o nazwie Suma(). Funkcja b�dzie pobiera�  
jako parametr ilo�� obiekt�w do zsumowania i sumowa� zawarto�ci  
wewn�trznych licznik�w obiekt�w.  
 
const MAX = 26; 
 
class Licznik  
{   
  char moja_litera;   
  int ile;  
public:   
  void Inicjuj(char);   
  void Skok_licznika();   
  void Pokazuj();  
  friend int Suma(int);  
} TAB[MAX]; 
 
Zadeklarowana w taki spos�b zaprzyja�niona funkcja ma prawo  
dost�pu do prywatnych element�w wszystkich obiekt�w klasy  
Licznik. Typowe zastosowanie funkcji typu friend polega w�a�nie  
na dost�pie do danych wielu r�nych obiekt�w. Powinni�my  
zsumowa� zawarto�� p�l  
 
TAB[i].ile  
 
dla wszystkich obiekt�w (od i = 0 a� do i = MAX). Zwr�� uwag�,  
�e definiuj�c funkcj� Suma() nie stosujemy powt�rnie s�owa  
kluczowego friend. A oto definicja:  
 
int Suma(int ilosc_obiektow)  
{  
      int i, suma = 0;  
   for(i = 0; i < ilosc_obiektow; i++)  
      suma += TAB[i].ile;  
 
      return (suma);  
}  
 
Dzi�ki zastosowaniu s�owa "friend", funkcja Suma() jest  
zaprzyja�niona ze wszystkimi 26 obiektami, poniewa� wszystkie  
obiekty nale�� do tej klasy, w kt�rej zadeklarowali�my funkcj�: 
 
class ...  
{  
 ... 
friend int Suma(...);  
 ...  
} ... ;  
 
Tablica TAB[MAX] z�o�ona z obiekt�w klasy Licznik zosta�a  
zadeklarowana nazewn�trz funkcji main() ma wi�c status tablicy  
GLOBALNEJ. Funkcja Suma() ma dost�p do prywatnych danych  
wszystkich obiekt�w, mo�emy wi�c zastosowa� j� w programie w  
nast�puj�cy spos�b: 
 
[P108.CPP] 
 
# include <ctype.h> 
# include <iostream.h>  
 
class Licznik  
{   
  char moja_litera;   
  int ile;  
public:   
  void Inicjuj(char);   
  void Skok_licznika();   
  void Pokazuj();  
  friend int Suma(int);  
}  
const MAX = 26; 
Licznik TAB[MAX]; 
register int i;   
 
main()   
{   
/* inicjujemy liczniki: -------------------------------*/  
  
for(i = 0; i < MAX; i++)   
   {   
     TAB[i].Inicjuj('A' + i);   
   }  
/* pracujemy - zliczamy: -------------------------------*/  
  
cout << "Wpisz ciag zankow zakonczony kropka [.]" << '\n';  
for(;;)   
  { char znak;  
    cin >> znak;  
    if(znak == '.') break;  
    for(i = 0; i < MAX; i++)   
       {   
         if(i == (znak - 'A')) TAB[i].Skok_licznika();   
       }   
  }  
/* sprawdzamy: ----------------------------------------*/  
  
char sprawdzamy;  
cout << '\n' << "Podaj znak do sprawdzenia: " << '\n';   
cin >> sprawdzamy;  
cout << "Wyswietlam wyniki zliczania: \n";   
  TAB[toupper(sprawdzamy) - 'A'].Pokazuj();   
  
cout << "\n Wszystkich liter bylo " << Suma(MAX); 
 
return 0;   
}  
 
void Licznik::Inicjuj(char zn)   
{   
  moja_litera = zn;   
  ile = 0;   
}   
  
void Licznik::Skok_licznika(void) { ile++; }  
  
void Licznik::Pokazuj(void)   
{   
  cout << "Znak " << moja_litera << " wystapil "   
       << ile << " razy" << '\n';   
}  
 
int Suma(int ilosc_obiektow)  
{  
      int i, suma = 0;  
   for(i = 0; i < ilosc_obiektow; i++)  
      suma += TAB[i].ile;  
 
      return (suma);  
}  
 
Tak dzia�a funkcja typu friend. Zwr��my tu uwag�, �e funkcja  
taka nie jest traktowana dok�adnie tak samo, jak metoda  
wchodz�ca w sk�ad klasy i obiektu. Metoda, czyli "w�asna"  
funkcja obiektu odwo�uje si� do jego pola (danych) w taki  
spos�b:  
 
void Licznik::Skok_licznika(void)  
{  
    ile++;                 //Wiadomo o ktory obiekt chodzi  
}  
 
Funkcja klasy friend odwo�uje si� do p�l obiekt�w tak:  
 
int Suma(int liczba)  
{  
 ... 
     suma += TAB[i].ile; 
/* - wymaga dodatkowo wskazania, o kt�ry obiekt chodzi - */ 
}  
 
Nale�y pami�ta�, �e dla funkcji kategorii friend wszystkie  
obiekty nale��ce do danej klasy maj� status public - s�  
dost�pne.  
 
O ZAPRZYJA�NIONYCH KLASACH.  
 
W C++ mog� by� zaprzyja�nione ze sob� wzajemnie tak�e klasy.  
Pozwala to metodom zdefiniowanym wewn�trz jednej z klas na  
dost�p do prywatnych danych obiekt�w innych klas. W przypadku  
zaprzyja�nionych klas s�owem kluczowym friend poprzedzamy nazw�  
klasy (a nie ka�dej zap...
Zgłoś jeśli naruszono regulamin