Wykład 2
Przeciw pełnej
hermetyzacji
Ukrywanie informacji - etykiety
private i public
Jeśli klasa ma etykietę private, to jej składniki będą dostępne tylko
w zakresie wnętrza klasy. Jeśli etykiet nie ma, to w trybie
domyślnym wszystkie składniki klasy są private. Są lokalne w
zakresie ważności klasy. Jeśli etykieta jest public, to składniki klasy
mogą być wywoływane także spoza tej klasy. Etykietami możemy
określać także dostęp do wybranych składników klasy wybiórczo
umieszczając etykietę przed nazwą składnika klasy. Wtedy private i
public mają sens podany wyżej. Dodatkowo stosuje się także etykietę
protected. Oznacza ona, że taki składnik jest dostępny tylko w
ramach dziedziczenia tj. w klasach, które są potomkami klasy
zawierającej ten składnik.
Tak więc etykiety właśnie zapewniają nam ochronę dostępu do
składników klasy. Dane najczęściej umieszczamy w klasach
chronionych czyli private. Do ustawiania wartości i pobierania
danych korzystamy z funkcji składowych klasy. To do nich stosujemy
etykiety ochrony. Etykiety te są jednym z narzędzi hermetyzacji
klasy.
Przykład:
class chamidlo
{
int a;
float b;
void fun1(int);
protected:
char m;
void fun2(void);
public:
int v;
void fun3(char*);
private:
int d;
void fun4(float b);
}
W tej klasie składniki prywatne, czyli dostępne tylko w obrębie
klasy chamidlo to: a,b,fun1,d, fun4. Składniki protected, czyli
zastrzeżone dla tej klasy i jej potomków to: m,fun2. Pozostałe
składniki są publiczne, czyli dostępne dla wszystkich elementów
programu. Są to: v, fun3.
Funkcje zaprzyjaźnione
To takie funkcje, które, mimo, że nie są składnikami klasy, to
mają dostęp do jej składników czyli innych funkcji, zmiennych i
obiektów. Mają dostęp także do tych składników klasy, które są
hermetyzowane etykietą private. Pamiętajmy, że jeśli nie ma innych
etykiet, to wszystkie składniki są private. Funkcja zaprzyjaźniona
jest wprowadzana instrukcją friend.
Sposób stosowania:
class figura{
int x,y;
…….
friend void goniec(figura&)
};
Sama funkcja goniec(figura&) jest zdefiniowana gdzieś w
programie w całkowicie innym miejscu nie powiązanym z
klasą pionek. W klasie figura {} chcemy z niej skorzystać
nawet, jeśli przynależy ona do innej klasy. Wtedy poprawnie
jest taką funkcję zaznaczyć etykietą public w jej klasie.
Cechy funkcji zaprzyjaźnionych:
*Funkcja może być zaprzyjaźniona z kilkoma klasami.
*Na argumentach jej wywołania może wykonywać operacje
zgodnie ze swoją definicją.
*Może być napisana w zupełnie innym języku niż C++ i
dlatego może nie być funkcją składową klasy.
*Ponieważ funkcja typu friend nie jest składnikiem klasy to nie ma
wskaźnika this, czyli musi się posłużyć operatorem wskaźnika, albo
przypisania aby wykonać działania (także te na składniku klasy, z
którą jest zaprzyjaźniona).
*Jest deklarowana w klasie ze słowem instrukcji friend i nie
podlega etykietom hermetyzcji (public, private, protected).
*Może być cała zdefiniowana w klasie i wtedy jest typu inline ale
nadal jest funkcją zaprzyjaźnioną.
*Nie musi być funkcją składową żadnej klasy ale może nią być.
*Klasa może się przyjaźnić z wieloma funkcjami, które są lub nie są
składnikami innych klas.
*Funkcje zaprzyjaźnione nie są przechodnie, to znaczy, że „przyjaciel
mego przyjaciela nie jest moim przyjacielem” czyli zaprzyjaźnienie
nie przenosi się od klasy do klasy.
*Zaprzyjaźnienie nie podlega mechanizmowi dziedziczenia.
*Z zasady umieszcza się funkcje zaprzyjaźnione na początku
wszystkich deklaracji w klasie.
Zaprzyjaźnienie klas
#include <string>
using namespace std;
class Pies {
string kolor, przedmiot;
int wiek; friend class Kot;
public:
Pies(string, int, string); void drukuj();
void zamien(Kot *);
};
class Kot { string kolor, przedmiot; int wiek;
friend class Pies;
public:
Kot(string, int, string); void drukuj();
void zamien(Pies *);
void clear() { przedmiot=""; }
};
Zaprzyjaźnienie klas cd.1
Pies::Pies(string aKolor, int aWiek, string aPrzedmiot)
{
• kolor = aKolor;
• wiek = aWiek;
• przedmiot = aPrzedmiot;
}
Kot::Kot(string aKolor, int aWiek, string aPrzedmiot)
{
• kolor = aKolor;
• wiek = aWiek;
• przedmiot = aPrzedmiot;
}
Zaprzyjaźnienie klas cd.2
• void Pies::zamien(Kot *b)
• {
• string old = b->przedmiot;
• b->przedmiot = przedmiot;
• przedmiot = old;
• }
• void Kot::zamien(Pies *b)
• {
• string old = b->przedmiot;
• b->przedmiot = przedmiot;
• przedmiot = old;
• }
Zaprzyjaźnienie klas cd.3
• void
• Pies::drukuj()
• {
• printf("Kolor [%s], wiek [%d], przedmiot [%s]\n",
kolor.c_str(), wiek,
• przedmiot.c_str());
• }
• void
• Kot::drukuj()
• {
• printf("Kolor [%s], wiek [%d], przedmiot [%s]\n",
kolor.c_str(), wiek,
• przedmiot.c_str());
• }
Zaprzyjaźnienie klas cd.4
int main(int argc, char* argv[])
{
• Pies a("czarny", 3, "kosc"); Kot b("bialy", 5, "pilka");
• a.drukuj(); b.drukuj();
• printf("\nZamiana...\n\n"); a.zamien(&b); a.drukuj();
b.drukuj();
• printf("\nA zabiera B...\n\n"); a.zamien(&b); b.clear();
• a.drukuj(); b.drukuj();
• printf("\n"); system("PAUSE");
•
return 0;
}
Cechy zaprzyjaźniania klas
• W klasie możemy deklarować przyjaźń z
funkcjami składowymi innej klasy bez ograniczeń.
Oznacza to, że obiekty klasy zaprzyjaźnionej i jej
składniki otrzymują dostęp do wszystkich – także
prywatnych – skłąadników klasy zaprzyjaźnionej.
• Jedną klasę możemy zaprzyjaźnić z wieloma
innymi klasami.
• Przyjaźń nie jest przechodnia.
• Zaprzyjaźnianie klas jest wyłączone z procesu
dziedziczenia, czyli zaprzyjaźnienie nie jest
dziedziczone.