background image

 

 

Struktury

Struktury

background image

 

 

Wskaźnik do struktury:

Jeśli 

do 

obiektu 

strukturalnego 

odwołujemy  się  za  pomocą 

wskaźnika

,  to 

dostęp  do  poszczególnych  pól  możemy 
uzyskać  przez  złożenie 

*

  i 

.

    lub  operator 

->

 ( znak 

-

 oraz znak 

>

 ):

Wskaźnik_Obiektu

 -> 

Nazwa_Składnika

(

* Wskaźnik_Obiektu

 ). 

Nazwa_Składnika

* Wskaźnik_Obiektu 

Nazwa_Składnika

background image

 

 

Każda definicja struktury wprowadza nowy, 
unikatowy typ, np.:

struct

 S1 

{

 

int

 

i; 

}

;

struct

 S2 

{

 

int

 

j; 

}

;

Typy 

S1

 i 

S2

 są różnymi typami, zatem w 

deklaracjach:

S1  x, y;
S2  z;

zmienne 

x

 oraz 

y

 są tego samego typu 

S1

natomiast 

x

 oraz 

z

 są różnych typów. 

background image

 

 

Wobec tego przypisania:

x = y;
y = x;

są 

poprawne

, podczas gdy:

x = z;
z = y;

są 

błędne

.

Dopuszczalne są natomiast przypisania 
składowych o tych samych typach, np.:

x.i = z.j;

background image

 

 

Przeładowanie  funkcji

background image

 

 

W jezyku C 

w danym zakresie ważności może być 
tylko 

jedna

 funkcja o danej nazwie.

Kompilator języka C++ daje nam większą 
swobodę.

Przykład

:

void

 pisz(

float

);

void

 pisz(

char

int

char

);

pisz(‘C’, 123, 
‘F’);

Czy masz 

wątpliwość o 

wywołanie jakiej 

funkcji chodzi?

background image

 

 

 Przeładowanie funkcji polega na tym, że 

w danym zakresie ważności jest więcej 
niż jedna funkcja o takiej samej nazwie.

 To, która z nich zostaje w danym 

przypadku uaktywniona zależy od typu 
argumentów podanych podczas 
wywołania. 

 Funkcje takie mają tę samą nazwę, ale 

muszą się różnić liczbą lub typem 
argumentów.

Przeładowujemy funkcję wówczas, gdy 
wykonuje ona analogiczną akcję na różnych 
zestawach obiektów
.

background image

 

 

void

 pisz (

int

 x);

void

 pisz (

int

 y);

// powtórna 

deklaracja

void

 pisz (

int

 , 

char

);

void

 pisz (

float

char

int

);

 Powtórna deklaracja nie jest błędem. 
 W przypadku deklaracji kompilator nie 

zareaguje.

 Zaprotestuje dopiero przy definicjach tych 

funkcji

(

patrz

 

PROG112.CPP

)

background image

 

 

int

 rysuj (

int

);

float

 rysuj (

int

);

Przy przeładowaniu ważna jest tylko odmienność 
argumentów.

int

 rysuj (

float

int

);

int

 rysuj (

int, 

float

);

BŁĄD !

POPRAWNIE 
!

background image

 

 

void

 pisz (

float

);

void

 pisz (

int

);

void

 pisz (

int

int

);

pisz (123, 
(

int

)45.67);

   void

 pisz (

int

int

);

void

 pisz (

int

int

);

void

 pisz (

int

unsigned

 

int

);

poprawnie 
!

background image

 

 

Przeładowanie przy argumentach 
domniemanych

void

 pisz (

float

);

void

 pisz (

char

 *);

void

 pisz (

int

float

 = 0);

pisz (5.67);

// 

pisz (

float

);

pisz (”2000 r.”);

// 

pisz (

char

 

*

);

pisz (123);

// 

pisz (

int

float

 = 

0);

pisz (123, 5.67);

// 

pisz (

int

float

);

void

 pisz (

int

);

background image

 

 

 W rzeczywistości funkcje przeładowane mają 

różne nazwy.

 Kompilator zmienia nazwy wszystkich funkcji 

programu.

 Kompilator uzupełnia nazwę funkcji dodając typ 

argumentów:

void

 rys(

void

 );

void

 rys (

void

 , 

float

);

void

 rys (

float

void

 );

void

 rys (

void

float

float

);

rys_Fv

rys_Fvf

rys _Ffv

rys _Fvf

 Zmiana nazwy funkcji dotyczy zarówno 

definicji i deklaracji funkcji, jak też i wywołań.

 Informacja o typie zwracanym nie  jest 

doczepiana do nazwy.

background image

 

 

 Rozwinięcie tej koncepcji stanowią szablony w 

niektórych jezykach nazywane typami ogólnymi 
(generic)

background image

 

 

Klasy

Klasy

background image

 

 

Definicja klasy:

class

 

identyfikator_typu

 

  

{

     

 ciało klasy

  

}

;

gdzie 

ciało 

klasy

 

zawiera 

deklaracje 

składników

 klasy.

class

 Okrag

  

{

     

public

:

        

int

 x, y, r;

        …
   

}

;

background image

 

 

Deklaracja  obiektu:

Okrag  Zielony;
Okrag  * Wskaz;
Okrag & Moj = Zielony;

Odwołanie się do składników  

obiektu:

obiekt .

 

składnik

wskaźnik ->

 

składnik

referencja .

 

składnik

background image

 

 

Zielony . r = 100;
Wskaz = & Zielony;
Wskaz -> r = 100;
Moj . r = 100;

Przykład:

Składnikami

 klasy mogą być też 

funkcje

class

 Okrag

{

   

public

:

      

int

 x, y, r;

           

void

  Inicjalizuj  ( 

int

  x1, 

int

  y1, 

int

 r1);

           

void

  Rysuj  ( 

int

  x1, 

int

  y1, 

int

 

r1);

}

;

background image

 

 

 W  ogólnym  przypadku  deklaracje  funkcji  w 

klasie  mogą  być  pomieszane  z deklaracjami 
danych. 

Składnik  jest  znany  w  całej  definicji  klasy

, 

niezależnie 

od 

miejsca 

zdefiniowania 

składnika wewnątrz klasy. 

 Nazwy  deklarowane  w  klasie  mają  zakres 

ważności równy obszarowi całej klasy.

 W  ciele  klasy,  jak  w  kapsule,  zamknięte  są 

dane oraz funkcje operujące na tych danych. 

 Takie  zamknięcie  nazywamy 

enkapsulacją

 

( od ang. 

encapsulation

).

 Funkcje składowe klasy mają zakres klasy. 

Uwagi:

background image

 

 

Ukrywanie  informacji:

class

 Moj_Typ

{

  

private

:

int

Liczba;

    

// prywatne dane składowe

float

Temperatura;

char

Komunikat [80];

int

  Czy_Gotowe(  );

         

//  prywatna  funkcja 

składowa

  

public

:

float

Predkosc;    

// publiczna dana składowa

int

Pomiar(  );      

//  publiczna  funkcja 

składowa

}

background image

 

 

Ukrywanie  informacji:

Są 

3

  etykiety,  za  pomocą  których  można 

określać dostęp do składników klasy:

private

:

protected

:

public

:

background image

 

 

Ukrywanie  informacji:

 Składnik 

private

:  jest  dostępny  tylko  dla 

składowych  danej  klasy.  Jeżeli  zależy  nam 
na  ukryciu  informacji,  to  wówczas  składnik 
powinien być deklarowany jako prywatny.

 Składnik 

protected

:  jest  dostępny  tak,  jak 

składnik 

private

,  ale  dodatkowo  jest 

dostępny dla  klas wywodzących się z danej 
klasy.

 Składnik 

public

jest 

dostępny 

bez 

ograniczeń.  Zwykle  składnikami  takimi  są 
wybrane  funkcje  składowe.  Za  ich  pomocą 
dokonujemy  z  zewnątrz  operacji  na  danych 
prywatnych.

 Etykiety  można  umieszczać  w  dowolnej 

kolejności, mogą też się powtarzać.

 Zakłada  się,  że  dopóki  w  definicji  klasy  nie 

wystąpi  żadna  z tych  etykiet,  składniki 
przez domniemanie mają dostęp 

private

.

background image

 

 

Klasa  a  obiekt :

class

 Osoba

{

   

char

 Nazwisko[40];

   

int

 Wiek;

   

public

:

void

 Zapamietaj (

char

 *, 

int

);

void

 Pisz ( );

}

;

Osoba

 

Student1

Student2

Asystent

 W pamięci utworzone zostały 3 różne 

komplety danych składowych (

Nazwisko

 i 

Wiek

). 

 Natomiast funkcje składowe są 

zapamiętane w pamięci 

tylko jednokrotnie

background image

 

 

Funkcje  składowe :

 Funkcje  składowe  mają 

pełny  dostęp  do 

wszystkich  składników  swojej  klasy

,  to 

znaczy: do danych (mogą z nich korzystać) i 
do innych funkcji (mogą je wywoływać). 

 Do składnika swojej klasy funkcje odwołują 

się przez podanie jego nazwy .

Nazwa_Obiektu .

 

Nazwa_Funkcji_Składowej

 

argumenty

 );

Student1 .

 

Zapamietaj

 

(Kowalski, 21);

background image

 

 

Osoba * Wsk;
Wsk = &Asystent; 
Osoba &Belfer = Asystent;

Wsk ->

 

Zapamietaj

 (Kowalski, 21);

Belfer.

 

Zapamietaj

 (Nowak, 30);

Możemy  także  wywołać  funkcję  składową 
dla  danego  obiektu,  pokazując  na  niego 

wskaźnikiem

 lub za pomocą 

referencji

 np.:

Funkcje  składowe :

background image

 

 

Definiowanie  funkcji  składowych :

Pierwszy sposób

wewnątrz definicji klasy

class

 Osoba

{

char

 Nazwisko [80];

// składniki prywatne

int

 Wiek;

public

:

// składniki publiczne

void

 Zapamietaj (

char

 * Napis, 

int

 Lata )

{

   strcpy (Nazwisko, Napis);
   Wiek = Lata;

}
void

 Pisz ( )

{

   cout 

<<

 Nazwisko 

<<

 

,  lat:

  

<<

 Wiek 

 

<<

 

endl

;

}

}

;

background image

 

 

Drugi sposób

: w 

definicji klasy

 umieszcza się 

tylko 

same deklaracje funkcji składowych

natomiast 

definicje są napisane poza ciałem 

klasy

class

 Osoba

{

char

 Nazwisko [80];

// składniki prywatne

int

 Wiek;

public

:

// składniki publiczne

void

 Zapamietaj (

char

 * Napis, 

int

 Lata );

void

 Pisz ( );

}

;

void

 Osoba::Zapamietaj (

char

 * Napis, 

int

 Lata )

{

   strcpy (Nazwisko, Napis);
   Wiek = Lata;

}
void

 Osoba::Pisz ( )

{

   cout 

<<

 Nazwisko 

<<

 

,  lat:

  

<<

 Wiek 

<<

 endl;

}

background image

 

 

 Ponieważ  funkcje  znajdują  się  teraz  poza 

definicją  klasy,  dlatego  ich  nazwa  została 
uzupełniona  nazwą  klasy,  do  której  mają 
należeć. Służy do tego operator zakresu 

::

.

 Funkcja  zdefiniowana  poza  klasą  ma  dokładnie 

taki  sam  zakres,  jakby  była  zdefiniowana 
wewnątrz klasy.

 Jednakże sposób definiowania funkcji wewnątrz, 

czy  na  zewnątrz  definicji  klasy  stanowi  różnicę 
dla kompilatora.

 Jeśli  bowiem  funkcję  składową  zdefiniowaliśmy 

wewnątrz  definicji  klasy

,  to  kompilator  uznaje, 

że chcemy, aby ta funkcja była typu 

inline

background image

 

 

inline

 

int

  Zaokr  ( 

float

 

Liczba);

{

   

return

 (Liczba + 0.5);

}

Funkcja typu 

inline

:

 Jeśli ciało funkcji składowej ma nie więcej 

niż  dwie  linijki,  to  funkcję  tę  definiujemy 
wewnątrz  klasy.  Jest  ona  automatycznie 

inline

.

 Jeśli  funkcja  składowa  jest  dłuższa  niż 

dwie  linijki,  to  definiujemy  ją  poza 
definicją 

klasy. 

Nie 

jest

 

ona 

automatycznie 

inline

background image

 

 

Funkcja  składowa  zdefiniowana  poza  definicją 
klasy  może  być  typu 

inline

,  ale  trzeba  to 

zaznaczyć pisząc słowo 

inline

, np.:

inline

  

void

 Osoba :: Pisz ( )

{

//

 

ciało funkcji

}

background image

 

 

Odwołanie 

się 

do 

publicznych 

danych 

składowych:

class

 Liczby

{

  

int

 L1:

  

public

 :

float

  L2;

void

 Fun ( );

}

;

Są tu dwie dane składowe. 

Składnik 

L1

 

jest 

prywatny

 

(przez 

domniemanie). 

Jako  prywatny  może  być 

dostępny  tylko  z 

zakresu  klasy

  -  czyli  wewnątrz  funkcji 

składowej 

Fun

.

background image

 

 

Składnik 

publiczny

 

L2

  oprócz  tego,  że  może 

być  dostępny  w  funkcji  składowej 

Fun

dostępny jest 

także z zewnątrz klasy

Pracując  jednak  na  nim  z zewnątrz  musimy 
podać, o który konkretnie obiekt chodzi, np.:

Liczby  Temperatura, Cisnienie;

Temperatura . L2 = 18.6;
Ciscienie . L2 = 1003;
cout 

<<

 

Temperatura 

wynosi 

:

 

 

<<

 

Temperatura . L2 
         

<<

  

stopni C\n

;

cout 

<<

  

Ciśnienie  wynosi:

   

<<

  Cisnienie  .  L2 

<<

  

hPa\n

;

background image

 

 

Zasłanianie nazw

Przesyłanie do funkcji argumentów będących 
obiektami

(

PROG57.CPP

)

 Przez domniemanie zakłada się, że 

obiekt jest przesyłany do funkcji 

przez 

wartość

.

 Konsekwencja: jeśli obiekt jest duży, to 

proces kopiowania może trwać długo. 

 Lepszym rozwiązaniem w takim 

przypadku jest przesyłanie 

przez 

referencję

.

background image

 

 

void

 Prezentacja (Osoba &Ktos)

{

 

cout 

<<

  

Mam  zaszczyt  przedstawić 

Państwu,\n

         

<<

 

Oto we własnej osobie:

  ;

cout 

<<

 Ktos . Pisz_Dane ();

}

background image

 

 

Konstruktor :

 Definicję  obiektu  i  nadanie  mu  wartości 

można załatwić w jednej instrukcji. 

 W tym celu należy posłużyć się specjalną 

funkcją składową zwaną 

konstruktorem

 Charakteryzuje  się  ona  tym,  że  nazywa 

się tak samo jak klasa. 

class

 Numer

{

   

int

 Liczba;

   

public

:

Numer  ( 

int

  L  ) 

{

  Liczba  =  L; 

}

 

// 

konstruktor

void

 Schowaj ( 

int

 L )  

{

 Liczba = L; 

}

int

 Zwracaj ( )         

{

 

return

  Liczba; 

}

}

 ;

(

PROG59.CPP

)

background image

 

 

Konstruktor

Klasy języka C++ wyposażone są w 
specjalną funkcję zwaną 

konstruktorem

;

Konstruktor

 jest specjalną  funkcją 

składową, wywoływaną zawsze w chwili 
tworzenia obiektu danej klasy;

Zadaniem konstruktora

 jest inicjalizacja 

danych składowych (pól) obiektu danej 
klasy, przydzielenie pamięci dla jego 
elementów oraz wykonanie innych 
czynności niezbędnych do prawidłowego 
utworzenia obiektu;

Konstruktor 

nie jest obowiązkowym

 

elementem definicji klasy.

background image

 

 

• Jeśli tworząc klasę nie zdefiniujesz jawnie 

jej konstruktora, kompilator automatycznie 
wygeneruje tzw. 

konstruktor domyślny

;

• Rozwiązanie takie, choć dość wygodne, 

sprawdza się tylko dla bardzo prostych klas;

• W praktyce każda definicja nietrywialnej 

klasy będzie zawierała konstruktor;

Nazwa konstruktora

 musi być taka sama, 

jak nazwa zawierającej go klasy;

Konstruktor

 nie może zwracać żadnej 

wartości.

Konstruktor

background image

 

 

• Klasa może posiadać 

więcej niż 

jeden konstruktor

;

• Jest to możliwe dzięki 

mechanizmowi 

przeładowania 

funkcji

;

Konstruktor

background image

 

 

Przypomnienie

 - niezainicjalizowane 

zmienne będą zawierały przypadkowe 

wartości;

• Reguła ta odnosi się również do klas;
• Dobra praktyka wymaga inicjalizowania 

wszystkich pól klasy;

Przypomnienie

 - konstruktora nie można 

wywołać jawnie;

• Wywołanie konstruktora następuje w 

chwili tworzenia obiektu danej klasy ;

• W chwili powoływania obiektu wybierasz 

również wersję konstruktora, jeżeli dana 

klasa definiuje ich więcej.

• Ciekawostki: niepubliczny konstruktor ?

Konstruktor

background image

 

 

Destruktor :

 Przeciwieństwem 

konstruktora 

jest 

destruktor

.

Destruktor

 to funkcja składowa klasy. 

Destruktor

  nazywa  się  tak  samo,  jak 

klasa  z  tym,  że  przed  nazwą  ma  znak 

~

 

(

tylda

). 

 Podobnie  jak  konstruktor  -  nie  ma  on 

określenia typu zwracanego.

Destruktor

 wywoływany jest wtedy, gdy 

obiekt danej klasy ma być zlikwidowany.

background image

 

 

Destruktor

 jest specjalną funkcją wywoływaną w 

chwili likwidacji obiektu danej klasy;

Destruktor

 jest funkcjonalnym przeciwieństwem 

konstruktora;

• Do jego zadań należy najczęściej 

zwalnianie 

zasobów

 wykorzystywanych przez obiekt i inne 

czynności natury porządkowej;

Destruktor

 nie jest obowiązkowym elementem 

klasy;

Destruktor

 możesz zdefiniować tylko raz ;

Destruktor

 jest funkcją bezparametrową i nie 

zwracającą żadnej wartości;

Nazwa

 składa się z 

nazwy klasy

 poprzedzonej 

znakiem

 ~

.

Destruktor

(p. 

PROG156.CPP, 

PROG157a.CPP

)

background image

 

 

Destruktor

 jest wywoływany w chwili 

usuwania obiektu danej klasy;

• Sama likwidacja obiektu może nastąpić 

poprzez

– usunięcie go ze stosu, jeśli jest to obiekt 

lokalny, a operująca na nim funkcja właśnie 
zakończyła działanie;

– lub w wyniku wywołania operatora 

delete

jeśli obiekt został utworzony dynamicznie.

• W obu przypadkach wywołanie 

destruktora jest ostatnią czynnością 
obiektu przed jego unicestwieniem;

Destruktor

background image

 

 

Pola

 

klasy

 to nic więcej, jak tylko jej lokalne 

zmienne;

Pola klasy

 funkcjonują tak samo, jak pola 

struktury i różnią się od ostatnich wyłącznie 

domyślną kategorią dostępu;

• Wewnątrz klasy wszystkie pola są swobodnie 

dostępne dla wszystkich funkcji składowych;

• Natomiast ich widoczność na zewnątrz klasy 

jest uwarunkowana kwalifikatorami dostępu;

• Pola w sekcjach 

private

 i 

protected

 są na 

zewnątrz niedostępne;

• Pola 

public

 mogą być czytane i zapisywane 

spoza klasy bez ograniczeń.

Pola

background image

 

 

• Rozwiązaniem problemu dostępu do pól 

prywatnych są specjalne funkcje klasy 
ustawiające i pobierające wartości tych pól;

• Funkcje te, zwane 

funkcjami udostępniającymi

deklarowane są oczywiście w 

sekcji publicznej

;

• Fundamentaliści: ” wszystkie pola klas powinny 

być prywatne, a dostęp do nich ma byś 
realizowany wyłącznie za pomocą funkcji 
udostępniających
”;

• Radykałowie: ” wręcz przeciwnie”;
• Wytyczenie granicy jest kwestią doświadczenia 

i zdrowego rozsądku;

• Jeśli nie wiesz, co robić z danym polem, umieść 

go w sekcji prywatnej.

Pola

background image

 

 

• Zestaw publicznych funkcji składowych powinien 

być ograniczony do niezbędnego minimum 
zapewniającego skuteczną komunikację z 
obiektami i kontrolowanie ich działania;

• Jeśli dana funkcja składowa nie musi być widoczna 

na zewnątrz, powinna być zadeklarowana jako 
prywatna;

• Jeśli dana funkcja składowa nie musi być widoczna 

na zewnątrz, ale powinna być dostępna dla klas 
pochodnych, powinna być zadeklarowana jako 
chroniona (

protected

);

• Jeśli zależy Ci na szybkim wykonaniu funkcji, a 

jednocześnie jest ona niewielka, możesz 
zadeklarować ją jako funkcję wstawianą (

inline

);

Funkcje

background image

 

 

• Deklaracja każdej klasy zawiera ukryte 

pole wskaźnikowe o nazwie 

this

;

• Po utworzeniu obiektu, wskaźnik 

this

 

zawiera adres obiektu w pamięci;

• Oto klasa 

Punkt

 widziana oczami 

komputera:

Wskaźnik this

Class

 Punkt

private

      Punkt *

this

;

      

int

 x, y;

    

public

:

        Punkt (

int

 _x, 

int

 _y);

        ~Punkt()
         ....
};

background image

 

 

• Czemu służy wskaźnik 

this 

?;

• Każdy obiekt danej klasy posiada własną 

kopię zestawu pól;

• Natomiast funkcje składowe są 

przechowywane w jednym egzemplarzu;

• Wskaźnik 

this

 pozwala na 

zidentyfikowanie właściciela danych, do 
których odwołuje się funkcja składowa;

• Jeśli chcesz uniknąć kłopotów, nigdy nie 

zmieniaj wartości wskaźnika 

this

!

Wskaźnik 

this

background image

 

 

Dziedziczenie

Dziedziczeniem

 nazywamy proces tworzenia 

nowych klas na podstawie klas już 
istniejących;

• Klasa wykorzystywana jako podstawa w 

procesie dziedziczenia jest 

klasą bazową

;

• Klasy dziedziczące po klasie bazowej są to 

klasy pochodne

;

• Klasa pochodna dziedziczy wszystkie 

możliwości funkcjonalne klasy bazowej, 
poszerzone o nowe pola i funkcje;

• Niemożliwe jest usunięcie jakichkolwiek 

elementów klasy bazowej.

background image

 

 

Dziedziczenie

• Samo dziedziczenie symbolizowane jest 

przez znajdujący się w pierwszym wierszu 
deklaracji klasy 

dwukropek

, po którym 

występuje nazwa klasy bazowej ;

• Słowo kluczowe 

virtual

 deklaruje 

poprzedzoną nim funkcję jako 

wirtualną

;

• Jako przykład funkcji wirtualnych rozpatrz 

funkcje o nazwie 

Pokaz()

 w klasach 

Punkt

 i 

Linia_Pozioma

;

• Ponieważ procedura narysowania na ekranie 

linii różni się od procedury narysowania 
punktu, należy w klasie 

Linia_Pozioma

 

przedefiniować (

przesłonić

) funkcję 

Pokaz()

.

background image

 

 

Przesłanianie

Przesłanianiem

 nazywamy przedefiniowywanie 

funkcji klasy bazowej w klasach pochodnych ;

• Przesłanianie stosuje się w celu całkowitej 

zmiany działania funkcji klasy bazowej lub, 
znacznie częściej, jej uzupełnienia i rozszerzenia 
o dodatkowe operacje;

• Aby rozszerzyć pierwotną definicję 

nie musisz jej 

przepisywać

. W nowej definicji funkcji wystarczy 

najpierw wywołać funkcję klasy bazowej, a 
następnie dopisać kod realizujący rozszerzenia;

• Przesłaniając funkcje klasy bazowej musisz 

zapewnić 

identyczność nagłówków funkcji

;

• Istotne jest również aby funkcja 

była dostępna 

dla klas pochodnych

.

background image

 

 

Przesłanianie

• Odwołując się do funkcji klasy bazowej musisz 

poprzedzić ją nazwą klasy i operatorem 
zakresu;

• Użycie operatora zakresu jest konieczne tylko 

wtedy, gdy wywoływana funkcja jest 
zdefiniowana zarówno w klasie bazowej, jak i 
pochodnej ;

• Jeśli funkcja jest zdefiniowana tylko w sekcji 

publicznej lub chronionej klasy bazowej, a nie 
wchodzi w skład definicji klasy pochodnej, 
możesz ją wywołać bez użycia operatora 
zakresu.

background image

 

 

Funkcje wirtualne

Funkcją wirtualną

 nazywamy funkcję 

wywoływaną zawsze w obrębie posiadającej ją 
klasy;

Poprzedzenie deklaracji słowem kluczowym 

virtual

 powoduje, że wszystkie odwołania do 

funkcji będą zawsze wykonywane w obrębie 
klasy, która ją zdefiniowała;

Jeśli podejrzewasz, że funkcja będzie 
przedefiniowywana w klasach pochodnych, 
warto deklarować ją jako wirtualną;

Jeśli przedefiniowywana funkcja jest 
wywoływana przez inne funkcje klasy 
bazowej, prawie na pewno powinieneś 
zadeklarować ją jako wirtualną.

background image

 

 

Inicjalizacja obiektów

• Kolejnym problemem związanym z 

dziedziczeniem jest 

inicjalizacja obiektów

;

• W chwili utworzenia obiektu klasy pochodnej 

należy zainicjalizować też pola klasy bazowej, 
a w przypadku dziedziczenia „piętrowego” - 
również wszystkich klas pośrednich;

• Najskuteczniejszym na to sposobem jest po 

prostu wywołanie konstruktora klasy bazowej 
w konstruktorze klasy pochodnej;

• Ponieważ nie można wywołać tego 

konstruktora bezpośrednio, należy 
wykorzystać w tym celu listę inicjalizującą

;

• Prawidłowa inicjalizacja klasy bazowej w 

konstruktorze klasy pochodnej jest sprawą 
bardzo istotną.


Document Outline