background image

 

 
 
 
 
 
 
 
 
 

Programowanie w j

ę

zyku C++ 

 
 
 
 
 
 
 
 

Krzysztof Karbowski 

 

Politechnika Krakowska 

 
 
 
 
 
 

Kraków 2003 

 

background image

Krzysztof Karbowski: Programowanie w języku C++ 

Wydanie: 24.10.2009 

background image

Krzysztof Karbowski: Programowanie w języku C++ 

Ś

rodowisko Visual Studio 2005. 

File – New – Project... : 
 

 

Rys.1. 

 

 

Rys.2 

 

 

background image

Krzysztof Karbowski: Programowanie w języku C++ 

Project – Add New Item … 

 

 

Rys.3. 

 
 
Kompilacja programu: „Build – Build Solution” (F7). 
Uruchomienie programu: "Debug – Debug Without Debugging" (Ctrl+F5) 

background image

Krzysztof Karbowski: Programowanie w j

Kompilator Dev-C++

 
 

 
 

File – New Project... 

 

Programowanie w języku C++ 

C++ 

www.bloodshed.net

 

 

 

background image

Krzysztof Karbowski: Programowanie w j

 

 
 

Programowanie w języku C++ 

 

 

 

 

background image

Krzysztof Karbowski: Programowanie w języku C++ 

1. Pierwszy program. 

wariant 1: 

#include <iostream
using namespace 
std; 
int main() 

 

cout << "Pierwszy program \n" 

 

return 0; 

 
wariant 2: 

  

#include <stdio.h> 
int main() 

 

printf("Pierwszy program \n") 

 

return 0; 

 
UWAGA: 

C++  jest  językiem  o  wolnym  formacie  zapisu.  Poza  nielicznymi 
wyjątkami  instrukcje  moŜna  zapisywać  w  dowolnym  miejscu.  Koniec 
instrukcji jest oznaczany znakiem „ ; ”. 

 
wariant 3: 

#include <stdio.h> 
main(){ printf("Pierwszy program \n"); return 0;} 

 
Kompilacja i konsolidacja programu: 

1.

 

kompilator 

2.

 

linker 

 

2. Drugi program 



 

/* -------------------------------------------------- 

Program na przeliczanie wysokosci podanej w stopach 
na wysokosc w metrach. 
Opearacje wejscia/wyjscia. 
---------------------------------------------------- */ 
#include <iostream
using namespace 
std; 
int main() 

int
 stopy;  

 

// definicja zmiennej 

float metry; 

 

 

// definicja zmiennej 

float przelicznik=0.3; 

// def. i inicjalizacja zmiennej 

 

 

 

cout << "Podaj wysokosc w stopach: " ; 

 

cin >> stopy ; 

 

// przyjecie danej z klawiatury 

 

metry = stopy * przelicznik ; 

 

cout << endl ; 

 

// wypisanie wynikow 

background image

Krzysztof Karbowski: Programowanie w języku C++ 

 

cout << stopy << " stop to " << metry  

<< " metrow \n" ; 

 

return 0; 

} 
 

3. Instrukcje steruj

ą

ce. 

3.1. Prawda – fałsz 

 

wartość zero   

odpowiada stanowi: fałsz (FALSE) 

 

wartość inna niŜ zero - 

odpowiada stanowi: prawda (TRUE) 

3.2. Instrukcja warunkowa if 

Forma 1: 
 

if (wyraŜenie) instrukcja1 ; 

Forma 2: 
 

if (wyraŜenie)  instrukcja1 ; 

 

else  

 

instrukcja2 ; 

 
Przykład: 

int i ; 
cout << Podaj liczbe: “ ; 
cin >> i ; 
if (i – 4) cout << "liczba rozna od 4" ; 
else       cout << "liczba rowna 4" ; 

Wybór wielowariantowy: 
 

if (wyraŜenie1)  

instrukcja1 ; 

 

else if (warunek2)  

instrukcja2 ; 

 

else if (warunek3)  

instrukcja3 ; 

3.3. Blok instrukcji 


 

instrukcja1 ; 

 

instrukcja2 ; 

 

instrukcjan ; 

} 

 
Przykład: 

int i ; 
cout << Podaj liczbe: “ ; 
cin >> i ; 
if (< 5) 

 

cout << "liczba mniejsza od 5" ; 

 

cout << endl ; 

 

= 5 ; 

}  // tu NIE MA srednika 
else 

 

cout << "Liczba nie jest mniejsza od 5" ; 

 

cout << endl ; 

background image

Krzysztof Karbowski: Programowanie w języku C++ 

3.4. Instrukcja while 

while (wyraŜenie) instrukcja ; 

Działanie: 
 

Wykonuj  instrukcję  tak  długo  jak  długo  wartość  wyraŜenia  jest  niezerowa.  Warunek 

sprawdzany jest przed wykonaniem instrukcji. 
 
Przykład: 

#include <iostream
using namespace 
std; 
int main() 

int
 ile ; 
 

 

 

cout << "podaj ilosc znakow: " ; 

 

cin >> ile ; 

 

// narysuj znaki x 

 

while (ile) 

 

 

  cout << "x" ; 

 

  ile = ile - 1 ; 

 

 

cout << endl 

 

return 0; 

3.5. P

ę

tla do ... while ... 

 

do instrukcja1 while (wyraŜenie; 

Działanie: 

Wykonuj  instrukcję  tak  długo  jak  długo  wartość  wyraŜenia  jest  niezerowa.  Warunek 

sprawdzany jest po wykonaniu instrukcji. 
 
Przykład: 

#include <iostream
using namespace 
std; 
int main() 

char
 litera; 
 
 

do 

 

 

  cout << "Podaj litere: " ; 

 

  cin >> litera ; 

 

  cout << "\nNapisales: " << litera << endl ; 

 

} while (litera != ‘k’); 

 

cout << "koniec petli\n" ; 

 

return 0; 

3.6. P

ę

tla for 

 

for (instrukcja_inicjalizująca ; wyraŜenie_warunkowe ; instrukcja_kroku) instrukcja ; 

 
Przykład: 

background image

Krzysztof Karbowski: Programowanie w języku C++ 

10 

for (= 0 ; i < 10 ; i=i+1) 

 

cout <<  "*" ; 

Działanie: 

1.

 

Wykonywana jest instrukcja inicjalizująca pętli. 

2.

 

Obliczane jest wyraŜenie warunkowe. Jeśli jest równe 0 to praca pętli jest przerywana. 

3.

 

JeŜeli wyraŜenie warunkowe jest róŜne od zera, to wykonywane są instrukcje będące 
treścią pętli. 

4.

 

Po wykonaniu treści pętli wykonywana jest instrukcja kroku, po czym powtarzana jest 
akcja 2. 

Przypadki szczególne: 

 

Instrukcja  inicjalizująca  nie  musi  być  jedną  instrukcją.  MoŜe  być  ich  kilka,  wtedy 
oddzielone są przecinkami. Podobnie jest w przypadku instrukcji kroku 

 

Elementy instrukcja_inicjalizująca , wyraŜenie_warunkowe oraz instrukcja_kroku nie 
muszą wystąpić. Dowolny z nich moŜna opuścić, zachowując średnik oddzielający go 
od sąsiada. Opuszczenie wyraŜenia warunkowego traktowane jest tak, jakby stało tam 
wyraŜenie zawsze prawdziwe. 

Przykład 

: 

#include <iostream> 
using namespace std; 
int main() 

int
 i, ile ; 
 
 

cout << "Podaj liczbe: " ; 

 

cin >> ile ; 

 

for (i=1; i<=ile; i=i+1) 

 

 

  cout << i << ". -*-" ; 

 

  cout << endl ; 

 

 

cout << "koniec petli\n" ; 

 

return 0; 

3.7. Instrukcja switch 

switch (wyraŜenie

case wart1
 

intrukcja1 ; 

case wart2
 

intrukcja2 ; 

default: 
 

instrukcja3 ; 

} 

Przykład 

: 

#include <iostream> 
using namespace std; 
// rozpoznawanie cyfr 
int main() 

background image

Krzysztof Karbowski: Programowanie w języku C++ 

11 

int liczba; 
 
 

cout << "Podaj liczbe: "; 

 

cin >> liczba; 

 

switch (liczba) 

 

 

case 1: 

 

  cout << "jeden" << endl; 

 

  break; 

 

case 2: 

 

  cout << "dwa" << endl; 

 

  // tu nie ma break 

 

case 3: 

 

  cout << "trzy" << endl; 

 

  break; 

 

default: 

 

  cout << "nie znam" << endl; 

 

  break; 

 

 

return 0; 

3.8. Instrukcja break 

Instrukcja break przerywa działanie pętli: 

 

for 

 

while 

 

do ... while 

Przykład: 

int i=7; 
while (1) 

 

i=i-1; 

 

if (i<5) break; 

3.9. Instrukcja goto 

 

goto etykieta ; 

Skok do miejsca w programie opatrzonego etykietą. 
Przykład: 

cout << "tekst 1" ; //zostanie wyswietlony 
cout << "tekst 2" ; //zostanie wyswietlony 
goto etykieta1; 
cout << "tekst 3" ; //nie zostanie wyswietlony 

etykieta1: 

cout << "tekst 4" ; //zostanie wyswietlony 

3.10. Instrukcja continue 

Instrukcja continue działa wewnątrz pętli: 

 

for 

 

while 

 

do ... while 

background image

Krzysztof Karbowski: Programowanie w języku C++ 

12 

i  powoduje  zaniechanie  wykonywania  instrukcji  wewnątrz  pętli  ale  nie  przerywa  działania 
pętli. 
 
Przykład: 

int i; 
for (i=0; i<10; i=i+1) 

 

cout << i; 

 

if (i>5) continue; 

 

cout << endl; 

} 
cout << endl; 

 
Inaczej moŜna by zapisać: 
 

int i; 
for (i=0; i<10; i=i+1) 
{ 
 

cout << i; 

 

if (i>5) goto koniec; 

 

cout << endl; 

 

koniec: 

} 
cout << endl; 

 

3.11. Klamry w instrukcjach steruj

ą

cych 

 
Przykład 1: 

while (< 4) { 
 

= i + 1 ; 

} 

Przykład 2 (Visual Studio 6.0): 

while (< 4)  
{ 

= i + 1 ; 

} 

Przykład 3: 

while (< 4)  

{ 
= i + 1 ; 
} 

 

4. Typy 

4.1. Deklaracje typów 

Deklaracja – informuje kompilator, Ŝe dana nazwa reprezentuje obiekt jakiegoś typu, ale nie 

rezerwuje dla niego miejsca w pamięci. 

Definicja  - dodatkowo rezerwuje miejsce w pamięci. 
 
Przykład: 

background image

Krzysztof Karbowski: Programowanie w języku C++ 

13 

int a ;  //deklaracja i definicja obiektu typu "int" o nazwie "a" 
extern int b;   //deklaracja obiektu typu "int" o nazwie "b"; 

//definicja wyst

ą

pi w innym miejscu 

4.2. Systematyka typów j

ę

zyka C++ 

 

 

typy fundamentalne 

 

typy pochodne 

 

 

typy wbudowane 

 

typy zdefiniowane przez uŜytkownika 

4.3. Typy fundamentalne 

4.3.1. Typy reprezentuj

ą

ce liczby całkowite 

 

short int

 

 

inaczej:  

short

 

 

int 

 

long int

 

 

inaczej: 

long

 

4.3.2. Typ reprezentuj

ą

cy znaki alfanumeryczne 

 

char 

4.3.3. Modyfikatory powy

Ŝ

szych typów: 

 

signed

   

liczba ze znakiem

 

 

unsigned 

liczba bez znaku (liczba dodatnia)

 

 
Przez domniemanie przyjmuje się, iŜ brak modyfikatora oznacza typ z modyfikatorem signed

4.3.4. Typy reprezentuj

ą

ce liczby zmiennoprzecinkowe 

 

float 

 

double 

 

long double 

 
Przykłady: 

int a ; 
short b ; 
short int c ; 
long double d ; 
unsigned int c ; 

4.4. Definiowanie obiektów “w biegu” 

#include <iostream> 
using namespace std; 
int main() 
{ 
int a ; 
 

 

 

a=1; 

 

int b;  // deklaracja/definicja obiektu 

background image

Krzysztof Karbowski: Programowanie w języku C++ 

14 

 

b=a+

 

cout << b

 

return 0; 

} 

4.5. Stałe dosłowne 

4.5.1. Stałe b

ę

d

ą

ce liczbami całkowitymi: 

np.: 

17 

-33 

 

1000

 

W układzie ósemkowym (zapis rozpoczyna się od cyfry 0): 

np.: 

010 

 

014 

 

061

 

W układzie szesnastkowym (zapis rozpoczyna się od 0x): 

np.: 

0x10   

0xa1   

0xff

 

 
Stałe całkowite traktowane są jak typ int, chyba Ŝe reprezentują liczby, które nie zmieściły by 
się w typie int – wtedy stała jest typu long
 
Wymuszenie typu stałej: 

200L

  - 

stała typu long 

277u

  - 

stała z modyfikatorem unsigned 

50uL

  - 

stała unsigned long 

4.5.2. Stałe reprezentuj

ą

ce liczby zmiennoprzecinkowe 

12.3   

-10.1  

10.4e-

4.5.3. Stałe znakowe 

a 

 

7 

Znaki specjalne: 

\n

  - 

nowa linia 

\t

  - 

tabulator 

\\

  - 

backslash 

\’’

  - 

apostrof 

\"‘

  - 

cudzysłów 

\0

  - 

znak o kodzie 0 (NULL) 

\?

  - 

znak zapytania 

4.5.4. Stałe tekstowe (ła

ń

cuchy tekstowe, stringi) 

"To jest ła

ń

cuch tekstowy" 

4.6. Typy pochodne 

Operatory umoŜliwiające tworzenie obiektów typów pochodnych: 

[]

 – tablica obiektów danego typu 

*

 – wskaźnik do obiektu danego typu 

()

 – funkcja zwracająca wartość danego typu 

&

 – referencja obiektu danego typu 

Przykłady: 

int t[10] ; 

// tablica 10 elementów typu int 

float *;  

// wska

ź

nik do obiektu typu float 

char func() ; 

//funkcja zwracaj

ą

ca obiekt typu char 

background image

Krzysztof Karbowski: Programowanie w języku C++ 

15 

5.6.1. Typ void 

void *;

    

-  oznacza, Ŝe p jest wskaźnikiem do obiektu nieznanego typu 

void funkcja();

  - funkcja nie zwraca wartości 

4.7. Zakres wa

Ŝ

no

ś

ci nazwy obiektu, a czas 

Ŝ

ycia obiektu 

Czas  Ŝycia  obiektu  –  okres  od  momentu  zdefiniowania  obiektu  (przydzielenia  miejsca  w 

pamięci) do momentu, gdy przestaje on istnieć (zwolnienia miejsca w pamięci). 

Zakres  waŜności  nazwy  obiektu  –  część  programu,  w  której  nazwa  znana  jest 

kompilatorowi. 

4.8. Zasłanianie nazw 

Przykład 

#include <iostream> 
using namespace std; 
int k=33;  // zmienna globalna 
int main() 
{ 
 

cout << "main (przed blokiem): k=" << k << endl; 

 

{  //poczatek bloku: zakres lokalny 

 

  int k=1; 

 

  cout << "blok: k=" << k << endl; 

 

  cout << "dostep do zmiennej globalnej k=" << 

 ::<< endl; 

 

}  //koniec bloku 

 

cout << "main (za blokiem): k=" << k << endl

 

return 0; 

} 

4.9. Modyfikator const 

SłuŜy do tworzenia obiektów stałych, których wartości nie da się zmienić. 

const float pi=3.1415927; 

Wartości tak zainicjalizowanego obiektu nie moŜna zmienić. 
 
Inicjalizacja – nadanie wartości obiektowi w momencie jego utworzenia. 
Przypisanie – wstawienie do obiektu wartości w jakimkolwiek późniejszym momencie. 
 
Obiekty const moŜna inicjalizować, ale nie moŜna do nich nic przypisać. 

4.10. Instrukcja typedef 

Pozwala na nadanie dodatkowej nazwy juŜ istniejącemu typowi. 

typedef int cena ; 
typedef char * napis ; 
cena x; 

 

//co odpowiada: int x; 

napis komunikat; 

//co odpowiada: char * komunikat; 

4.11. Typy wyliczeniowe enum 

 

enum nazwa_typu {lista_wyliczeniowa} ; 

Przykład: 

enum liczby { zero, jeden, dwa, trzy }; 
enum liczby2 
{ 

background image

Krzysztof Karbowski: Programowanie w języku C++ 

16 

 

jedenascie=11, 

 

trzynascie=13, 

 

dwadziescia=20 

}; 
liczby a;   

//definicja zmiennej 

liczby2 b;  

//definicja zmiennej 

 
 

a=zero; 

 

b=dwadziescia; 

 

5. Operatory 

5.1. Operatory arytmetyczne 

+

 

dodawanie 

-

 

odejmowanie 

*

 

mnoŜenie 

/

 

dzielenie 

Przykład: 

= b + c ; 
= b – c ; 
= b * c ; 
= b / c ; 
= (+ d + 3.1) / f ; 

5.1.1. Operator modulo 

Oblicza resztę z dzielenia 

= b % c ; 

5.1.2. Jednoargumentowe operatory + i – 

Przykład:  

+12.7          -x          -(a*b) 

5.1.3. Operatory inkrementacji i dekrementacji 

= i + 1 ;

     

moŜna zastąpić      

i++ ;

 

= k – 1;

     

moŜna zastąpić      

k--;

 

Formy operatorów: 

 

przedrostkowa  (prefix): 

++a

  lub 

--b  . 

Najpierw  zmieniana  jest  wartość  zmiennej,  a 

następnie zmieniona wartośc staje się wartością wyraŜenia. 

 

końcówkowa (postfix): 

a++

 lub 

b-- . 

Wartość zmiennej staje się wartością wyraŜenia, a 

następnie zmieniana jest wartość zmiennej. 

Przykład: 

int a=0; 
int b=0; 
cout << ++<< endl;  // pojawi si

ę

 1 

cout << b++ << endl;  // pojawi si

ę

 0 

cout << a << endl;    // pojawi si

ę

 1 

cout << b << endl;    // pojawi si

ę

 1 

5.1.4. Operator przypisania = 

 

= 27.

background image

Krzysztof Karbowski: Programowanie w języku C++ 

17 

Do  obiektu  stającego  po  lewej  stronie  operatora  =  wstawiona  zostaje  wartość  wyraŜenia 
stojącego po prawej. 

5.2. Operatory logiczne 

5.2.1. Operatory relacji 

 

<

 

mniejszy niŜ ... 

 

<=

 

mniejszy lub równy 

 

>

 

większy niŜ ... 

 

>=

 

większy lub równy 

 

!=

 

róŜny 

 

= =

 

równy 

Przykład 

 : 

#include <iostream> 
using namespace std; 
int main() 
{ 
int a=10; 
int b=5; 
 
 

cout << "a=" << a << " b=" << b << endl; 

 

if (a=b) 

// tu powinno byc a==

 

  cout << "a=b" << endl; 

 

else 

 

  cout << "a!=b" << endl

 

return 0; 

} 

PowyŜszy program wyświetli informacje, Ŝe a=b, gdyŜ w wyraŜeniu warunkowym instrukcji 
if  znajduje  się  instrukcja  przypisania  a  nie  operator  relacji.  Instrukcja  przypisania  jest 
wyraŜeniem,  a  więc  ma  wartość  (wartość  wyraŜenia  po  prawej  stronie  znaku  =).  W  tym 
przypadku  jest  to  wartość  5,  która  jest  róŜna  od  zera,  a  więc  zostanie  zinterpretowana  jako 
"prawda". 

5.2.2. Operatory sumy i iloczynu logicznego 

 

||

 

suma logiczna – operacja logiczna "lub" (alternatywa) 

 

&&

 

iloczyn logiczny – operacja logiczna "i" (koniunkcja) 

Przykład: 

int k=2; 
if ((k==10) || (k==2)) 
 

cout << "k równe 2 lub 10 \n" ; 

if ((k>=0) && (k<=10)) 
 

cout << "k nalezy do przedzialu [0,10] \n" ; 

5.2.3. Operator negacji logicznej 

 

! wyraŜenie 

Przykład: 

int i = 0 ; 
if (!i) 
 

cout << "tekst\n" ; 

background image

Krzysztof Karbowski: Programowanie w języku C++ 

18 

5.3. Operatory bitowe 

 

zmienna 

<<

 ile_miejsc 

przesunięcie w lewo 

zmienna 

>>

 ile_miejsc 

przesunięcie w prawo 

zmienna1 

&

 zmienna2   

bitowy iloczyn logiczny (AND) 

zmienna1 

|

 zmienna2   

bitowa suma logiczna (OR) 

zmienna1 

^

 zmienna2   

bitowa róŜnica symetryczna (XOR) 

~

 zmienna 

  

 

bitowa negacja 

5.4. Pozostałe operatory przypisania 

operator 

zamiennik 

= i + 2  i += 2 
= i – 2  i -= 2 
= i * 2  i *= 2 
= i / 2  i /= 2 
= i % 2  i %= 2 
= i >> 2 i >>= 2 
= i << 2 i <<= 2 
= i & 2  i &= 2 
= i | 2  i |= 2 
= i ^ 2  i ^= 2 

5.5. Wyra

Ŝ

enie warunkowe 

 

(warunek) ? wartość1 : wartość2 

JeŜeli  warunek  ma  wartość  niezerową  to  wartością  wyraŜenia  stanie  się  wartość1  –  w 
przeciwnym wypadku wartość2
Przykład: 

int a; 
a=5; 
= (a<10) ? 0 : 100 ; 

// zmiennej c zostanie przypisane 0 

5.6. Operator sizeof 

Zwraca rozmiar obiektu lub typu. 

 

sizeof(nazwa_typu) 

lub 

 

sizeof(nazwa_obiektu) 

Zwrócona liczba jest typu 

size_t

 (inaczej: 

unsigned int

). 

Gdy  argumentem  operatora  jest  nazwa  tablicy  statycznej  zwraca  rozmiar  tablicy  w  bajtach. 
Nie  jest  w  stanie  określić  rozmiaru  tablicy  alokowanej  dynamicznie  oraz  tablicy  będącej 
parametrem formalnym funkcji. 

5.7. Operator rzutowania 

 

(nazwa_typu)obiekt 

lub 

 

nazwa_typu(obiekt) 

UmoŜliwia przekształcenie typu obiektu. 
Przykład: 

int a; 
float b=10.1; 
a=(int)b; 
cout << a << endl; 

//zostanie wyswietlona wartosc 10 

background image

Krzysztof Karbowski: Programowanie w języku C++ 

19 

5.8. Operator przecinek 

UmoŜliwia grupowanie wyraŜeń. 

(2+4, a*4, 3<6, 77+2) 

WyraŜenia  składowe  obliczane  są  od  lewej  do  prawej.  Wartością  całego  wyraŜenia  staje  się 
wartość wyraŜenia znajdującego się najdalej z prawej strony. 

5.9. Programy przykładowe 

Przykład 

: 

Temat: Program dodający dwie liczby rzeczywiste. 

#include <iostream> 
using namespace std; 
int main() 
{ 
float a, b, wynik; 
 
 

cout << "Podaj pierwsza liczbe: "

 

cin >> a; 

 

cout << "Podaj druga liczbe: "

 

cin >> b; 

 

wynik=a+b; 

 

cout << "Suma: " << wynik << endl; 

 

return 0; 

} 

 
Przykład 

: 

Temat: Drukowanie alfabetu. 

#include <iostream> 
int main() 
{ 
char znak; 
 
 

for (znak=‘a; znak<=‘z; znak++) 

 

  cout << znak ; 

 

cout << endl ; 

 

return 0; 

} 

Przykład 

: 

Temat: Obliczanie n! . 
 

#include <iostream> 
using namespace std; 
int main() 
{ 
unsigned long silnia, liczba, licz; 
 
 

cout << "Podaj liczbe: "

 

cin >> liczba; 

 

silnia=1; 

 

licz=2; 

 

if (liczba) 

 

  while (licz<=liczba) //for ( ; licz<=liczba; ) 

 

  { 

 

   

silnia *= licz; 

background image

Krzysztof Karbowski: Programowanie w języku C++ 

20 

 

   

licz ++

 

  } 

 

cout << liczba << "! =" << silnia << endl; 

 

return 0; 

} 

 
Przykład 

: 

Temat: Wyjście z pętli gdy wprowadzona liczba jest równa zero. 
 

#include <iostream> 
using namespace std; 
int main() 
{ 
int liczba; 
 

 

 

do 

 

{ 

 

  cout << "Podaj liczbe: "

 

  cin >> liczba; 

 

  if (!liczba) cout << "zero - koniec petli\n"

 

  else cout << "To nie jest zero\n"

 

} while (liczba)

 

return 0; 

} 

 
Przykład 

: 

Temat:  Program  pobiera  dwie  liczby  a  następnie  kod  operacji:  0  –  koniec;  1  –  suma;  2  – 

róŜnica; 3 – iloczyn; 4 – iloraz. Wyświetla wynik obliczeń. 

 

#include <iostream> 
int main() 

float a, b; 
int kod; 
 

 

 

do 

 

 

  cout << "Wprowadz a= "; 

 

  cin >> a; 

 

  cout << "Wprowadz b= "; 

 

  cin >> b; 

 

  cout << "0:koniec; 1:(+); 2:(-); 3:(*); 4:(/)." << 

   "Podaj kod: "; 

 

  cin >> kod; 

 

  switch (kod) 

 

  { 

 

  case 0: 

 

   

cout << "Koniec pracy\n"; 

 

   

break

 

  case 1: 

 

   

cout << a << "+" << b << "=" << a+b << endl; 

 

   

break

 

  case 2: 

 

   

cout << a << "-" << b << "=" << a-b << endl; 

 

   

break

background image

Krzysztof Karbowski: Programowanie w języku C++ 

21 

 

  case 3: 

 

   

cout << a << "*" << b << "=" << a*b << endl; 

 

   

break

 

  case 4: 

 

   

cout << a << "/" << b << "=" << a/b << endl; 

 

   

break

 

  default

 

   

cout << "Nieznany kod operacji\n"; 

 

   

break

 

  } 

 

while (kod);  //while (kod!=0); 

return 0; 
}  

6. Funkcje 

Przykład 

: 

 

#include <iostream> 
using namespace std; 
char literki(int ile)

 

//deklaracja funkcji 

//---------------------------------------------- 
int main() 
{ 
int m; 
char znak; 
 

cout << "Podaj ilosc literek: "

 

cin >> m; 

 

znak=literki(m)

 

cout << "Drukowano litere " << znak << endl; 

 

return 0; 

} 
//---------------------------------------------- 
// Definicja funkcji 
char literki(int ile) 
{ 
int i; 
 

for (i=0; i<ile; i++) 

 

  cout << "f"

 

cout << endl; 

 

return f

} 

6.1. Zwracanie rezultatu przez funkcj

ę

 

Przykład 

:  Temat: Program obliczający potęgi liczb całkowitych z podanego przedziału. 

#include <iostream> 
using namespace std; 
long potega(long liczba, int stopien)
void koniec()
//------------------------ 
int main() 
{ 
long pocz, kon, i; 
 

cout << "Podaj poczatek przedzialu: "

 

cin >> pocz; 

background image

Krzysztof Karbowski: Programowanie w języku C++ 

22 

 

cout << "Podaj koniec przedzialu: "

 

cin >> kon; 

 

for (i=pocz; i<=kon; i++) 

 

{ 

 

  cout << i << "^2=" << potega(i,2) << "\t"

 

  cout << i << "^3=" << potega(i,3) << endl; 

 

} 

 

koniec()

 

return 0; 

} 
//-------------------------- 
long potega(long liczba, int stopien) 
{ 
long wynik=liczba; 
int i; 
 

for (i=1; i<stopien; i++) 

 

  wynik *= liczba; 

 

return wynik; 

}//---------------- 
void koniec() 
{ 
 

cout << "\nKONIEC PRACY\n"

} 

6.2. Przesyłanie argumentów 

Rodzaje przesyłania argumentów do funkcji: 

 

przez wartość, 

 

przez referencję, 

 

przez wskaźnik. 

 
Przykład 

: 

Temat: przesyłanie argumentów przez wartość i przez referencję. 

#include <iostream> 
using namespace std; 
//--------------------------- 
void zeruj(int a, int &b) 
{ 
 

cout << "-------------\n"

 

cout << "Funkcja\n"

 

cout << "a=" << a << "\tb=" << b << endl; 

 

a=0; b=0; 

 

cout << "Po wyzerowaniu:\n"

 

cout << "a=" << a << "\tb=" << b << endl; 

 

cout << "-------------\n"

 

return; 

} 
//--------------------------- 
int main() 
{ 
int A=7, B=77; 
 

cout << "Main\n"

 

cout << "A=" << A << "\tB=" << B << endl; 

 

zeruj(A,B)

 

cout << "Main\n"

background image

Krzysztof Karbowski: Programowanie w języku C++ 

23 

 

cout << "Po wywolaniu funkcji:\n"

 

cout << "A=" << A << "\tB=" << B << endl; 

 

return 0; 

} 

6.3. Argumenty domniemane 

Przykład: 
Deklaracje funkcji: 

void funkcja1(int arg1, int arg2=0)
void funkcja2(float arg1, int arg2=1, int arg3=5)

Wywołanie funkcji: 

funkcja1(10)

 

 

funkcja1(10,0)

funkcja1(-10,5)

funkcja2(-2.1,-5)

 

funkcja2(-2.1,-5,5)

funkcja2(-1, ,3)

 

tak jest 

Ź

LE 

 
Określenie  argumentów  domniemanych  musi  wystąpić  w  deklaracji 
funkcji lub w definicji, która jest jednocześnie deklaracją. 

6.4. Funkcje inline 

Przykład: 

inline int dodaj(int a, int b) 
{ 
 

return a+b; 

} 

Kompilator  utworzy  kod,  w  którym  w  miejscu  wywołania  funkcji  zostanie  wstawiony  kod 
definiujący funkcję, a nie skok do miejsca definicji funkcji. 

Definicja funkcji inline musi znajdować się przed jej wywołaniem, gdyŜ 
w  momencie  wywołania  funkcja  musi  być  znana  kompilatorowi  –  nie 
wystarczy deklaracja funkcji. 

6.5. Zakresy wa

Ŝ

no

ś

ci nazw deklarowanych wewn

ą

trz funkcji 

 

Zakres waŜności nazw deklarowanych w obrębie funkcji ogranicza się tylko do bloku tej 
funkcji. Nie moŜna spoza funkcji za pomocą danej nazwy próbować dotrzeć do zmiennej 
będącej w obrębie funkcji 

 

Nie  moŜna  wykonać  instrukcji  goto  spoza  funkcji  do  etykiety  zdefiniowanej  wewnątrz 
funkcji. 

6.6. Wybór zakresu wa

Ŝ

no

ś

ci nazwy i czasu 

Ŝ

ycia obiektu 

6.6.1. Obiekty globalne 

Obiekty zadeklarowane na zewnątrz wszystkich funkcji. 
Zakres waŜności: plik programu. 
Czas Ŝycia: czas działania programu. 
Wartość początkowa: 0 

6.6.2. Obiekty automatyczne 

Obiekty  zadeklarowane  wewnątrz  bloku  programu  (np.  wewnątrz  funkcji,  bloku 
instrukcji). 
Zakres waŜności: blok programu. 

background image

Krzysztof Karbowski: Programowanie w języku C++ 

24 

Czas Ŝycia: od momentu wystąpienia definicji do końca bloku. 
Wartość początkowa: przypadkowa. 

6.6.2. Obiekty lokalne statyczne 

Obiekty  zadeklarowane  wewnątrz  bloku  programu  (np.  wewnątrz  funkcji,  bloku 
instrukcji) i poprzedzone słowem 

static

Przykład:  

static int a; 
static float b=2.1; 

Zakres waŜności: blok programu. 
Czas Ŝycia: czas działania programu. 
Wartość początkowa: 0. 

background image

Krzysztof Karbowski: Programowanie w j

6.7. Obiekty w programie składaj

Przykład 

 : 

 
Plik main.cpp

#include <iostream
using namespace std;
#include "funkcja1.h"
#include "funkcja2.h"
int a; 

//definicja zmien

int main() 

int x, y; 
 

cout << "Podaj zmienna globalna a=";

 

cin >> a; 

 

cout << "Podaj x=";

 

cin >> x; 

 

cout << "Podaj y=";

 

cin >> y; 

 

Wypisz_a(); 

 

cout << "x+y=" << dodaj(x,y) << endl;

 

cout << "x-y=" << odejmij(x,y) << endl;

return 0; 

Plik funkcja1.cpp

#include <iostream
using namespace std;
extern int a; 

//deklaracja zmiennej globalnej

//--------------------------
int dodaj(int a, 

 

return a+b; 


//-------------------------

Programowanie w języku C++ 

6.7. Obiekty w programie składaj

ą

cym si

ę

 z kilku plików

 

iostream> 

std; 

#include "funkcja1.h" 
#include "funkcja2.h" 

//definicja zmiennej globalnej 

cout << "Podaj zmienna globalna a="; 

cout << "Podaj x="; 

cout << "Podaj y="; 

cout << "x+y=" << dodaj(x,y) << endl; 

y=" << odejmij(x,y) << endl; 

iostream> 

std; 

//deklaracja zmiennej globalnej 

-------------------------- 

a, int b) 

------------------------- 

25 

 z kilku plików 

background image

Krzysztof Karbowski: Programowanie w języku C++ 

26 

void Wypisz_a() 

 

cout << "\nZmienna globalna a=" << a << endl; 

Plik funkcja2.cpp: 

int odejmij(int a, int b) 

 

return a-b; 

Plik funkcja1.h

int dodaj(int a, int b); 
void Wypisz_a(); 

Plik funkcja2.h

int odejmij(int a, int b); 

 

6.7.1. Nazwy statyczne globalne 

Deklaracje globalne poprzedzone słowem 

static

Nazwa ta nie będzie znana w innych plikach. 
 

7. Preprocesor 

7.1. Dyrektywa #define 

 

#define wyraz ciąg znaków zastępujących go 

Kompilator zamieni wszelkie wystąpienia wyrazu ciągiem znaków zastępujących go. 
 
Przykład 1: 

#define DWA 2 
i=DWA + 2; 

Przykład 2: 

#define DO_START  

do { 

#define DO_STOP  

}while (!stop)

DO_START 
 

a=a+1; 

 

cin >> stop; 

DO_STOP 

7.2. Makrodefinicje 

 

#define wyraz(parametry) ciąg znaków zastępujących go 

Kompilator  zamieni  wszelkie  wystąpienia  wyrazu  ciągiem  znaków  zastępujących  go 
uwzględniając parametry. Stąd w makrodefinicjach najczęściej występuje nadmiar nawiasów, 
aby ustrzec się przed potencjalnymi błędami. 
 
Przykład: 

#define KWADRAT(a) 

((a) * (a)) 

wynik=KWADRAT(liczba)

zostanie zamienione na: 

wynik=((liczba) * (liczba)) ; 

background image

Krzysztof Karbowski: Programowanie w języku C++ 

27 

7.3. Dyrektywy kompilacji warunkowej 

#if warunek 
 

linie kompilowane warunkowo 

#endif 

lub 

#if warunek 
 

linie kompilowane warunkowo 

#else 
 

linie kompilowane warunkowo 

#endif 

lub 

#ifdef nazwa 
 

linie kompilowane warunkowo 

#else 
 

linie kompilowane warunkowo 

#endif 

lub 

#ifndef nazwa 
 

linie kompilowane warunkowo 

#else 
 

linie kompilowane warunkowo 

#endif 

 
Przykład 1: 
 

#define WARIANT 1 
#if (WARIANT==1) 
 

// linie programu 

 

// ............. 

#else 
 

// linie programu 

 

// ............. 

#endif  //WARIANT==

7.4. Wstawianie innych plików 

#include <nazwa_pliku_1> 
#include "nazwa_pliku_2" 

 
Przykład: 
Zabezpieczenie przed wielokrotnym dołączeniem pliku: 

#ifndef PLIK1_H 
#define PLIK1_H 
 

// zwykla tresc pliku 

 

// .................. 

#endif //PLIK1_H 

7.5. Dyrektywa #undef 

Przykład 

#define ABC 

 

// zaczyna obowiazywac nazwa ABC  

// ................... 
// linie programu 

background image

Krzysztof Karbowski: Programowanie w języku C++ 

28 

// ..................... 
#undef ABC  

// przestaje obowiazywac nazwa ABC 

// ..................... 

8. Tablice 

Definicja tablicy: 

typ nazwa[rozmiar]; 

Rozmiar tablicy musi być stałą znaną w trakcie kompilacji. 

Przykłady: 

char zdanie[80]

// tablica o nazwie zdanie zawierajaca  

 

   

 

// 80 elementów typu char 

float numer[9]// tablica 9 elementow typu float 
int *wskaz[20]// tablica 20 element bedacych wskaznikami 
 

   

 

// obiektow typu int 

 

Tablice moŜna tworzyć z: 

 

typów fundamentalnych (za wyjątkiem void), 

 

typów wyliczeniowych (enum), 

 

wskaźników, 

 

innych tablic, 

 

z obiektów typu zdefiniowanego przez uŜytkownika, 

 

ze wskaźników do pokazywania na składniki klasy. 

8.1. Elementy tablicy 

Tablica: 

int t[4]

składa się z następujących elementów: 

t[0]  t[1]  t[2]  t[3] 

 
Numeracja elementów tablicy zaczyna się od zera. 

 
Dla zdefiniowanej powyŜej tablicy moŜliwe są m.in. następujące instrukcje przypisania: 

t[0]=1; 
t[1]=23; 
t[2]=-5; 
t[3]=10; 

PoniŜsze przypisanie RÓWNIEś ZOSTANIE WYKONANE

t[4]=1; 

 

   Kompilator C++ nie sprawdza zakresu indeksów tablicy      

 
Sposób obliczenia rozmiaru tablicy (nie dotyczy tablicy dynamicznej i parametru formalnego 
funkcji): 

size_t rozmiar = sizeof(tab)/sizeof(tab[0])
 

Przykład 

 : 

#include <iostream> 
using namespace std; 
int main() 
{ 
int t[4]

background image

Krzysztof Karbowski: Programowanie w języku C++ 

29 

 

for (int i=0; i<4; i++) 

 

  t[i]=2*i; 

 

for (i=0; i<4; i++) 

 

  cout << "t[" << i << "]=" << t[i] << endl; 

 

return 0; 

} 

8.2. Inicjalizacja tablic 

Przykłady: 

int tab1[4] = { 17, 5, 4, 200 }
int tab2[4] = { 3,-}

// pozostałe elementy zostan

ą

  

 

   

 

 

 

// zainicjalizowane wartoscia 0 

int tab3[] = {-3, 1, 6, 8 }

// zostanie zdefiniowana  

 

   

 

 

 

 

// tablica "int tab3[4]" 

8.3. Przekazywanie tablic do funkcji 

Nazwa tablicy jest równocześnie adresem jej zerowego elementu. 

 
Tablice przesyła się podając funkcji tylko adres początku tablicy. 
Przykład 

: 

#include <iostream> 
using namespace std; 
void dodaj2(int tablica[], int ile)
//---------------------------- 
int main() 
{ 
const int rozmiar=4; 
int tab[rozmiar]

// mo

Ŝ

na wykorzystac zmienna rozmiar  

 

   

 

 

// gdyz jest to zmienna z modyfikatorem 

 

   

 

 

// const 

int i; 
 

for (i=0; i<rozmiar; i++) 

 

  tab[i]=i; 

 

dodaj2(tab,rozmiar)

 

for (i=0; i<rozmiar; i++) 

 

  cout << "tab[" << i << "]=" << tab[i] << endl; 

 

return 0; 

} 
//------------------------------- 
void dodaj2(int tablica[], int ile) 
{ 
int i; 
 

for (i=0; i<ile; i++) 

 

  tablica[i] += 2; 

} 

Przykład 

: 

#include <iostream> 
using namespace std; 
#define ROZMIAR 4 
void dodaj2(int tablica[ROZMIAR])
//---------------------------- 
int main() 
{ 
int tab[ROZMIAR]

  

background image

Krzysztof Karbowski: Programowanie w języku C++ 

30 

 

   

 

 

 

 

   

 

 

 

int i; 
 

for (i=0; i<ROZMIAR; i++) 

 

  tab[i]=i; 

 

dodaj2(tab)

 

for (i=0; i<ROZMIAR; i++) 

 

  cout << "tab[" << i << "]=" << tab[i] << endl; 

 

return 0; 

} 
//------------------------------- 
void dodaj2(int tablica[ROZMIAR]) 
{  // ROZMIAR nie jest konieczny, gdyz funkcja nie korzysta z 
tej  
 

// informacji 

int i; 
 

for (i=0; i<ROZMIAR; i++) 

 

  tablica[i] += 2; 

} 

W funkcji do określenia rozmiaru tablicy nie moŜna wykorzystać operatora 

sizeof

, gdyŜ na 

podstawie parametru formalnego nie da się określić rozmiaru elementu. 

8.4. Tablice znakowe 

 
Łańcuch znaków (string) – ciąg znaków alfanumerycznych zakończony znakiem o kodzie 0 

(\0 – NULL). 

Przykłady tablic znakowych: 

char zdanie[80]

// tablica do przechowywania 80 elementów  

 

   

 

// b

ę

d

ą

cych znakami. 

char sTab[10] = { "lancuch" }

sTab:  

l  a  n  c  u  c  h  NULL  0  0 

 
Inne sposoby inicjalizacji: 

char sTab[10] = { k’, o’, t }

k  o  t  0  0  0  0  0  0  0 

 

PoniewaŜ NULL ma kod 0, więc łańcuch zostanie poprawnie zakończony. 

 

char sTab[] = { k’, o’, t }

k  o  t 

 

Kompilator  określi  rozmiar  tablicy  na  podstawie  liczby  elementów  na  liście 

inicjalizacyjnej.  Nie  ma  tam  znaku  NULL,  a  więc  nie  jest  to  tablica  przechowująca  łańcuch 
znakowy. 
 

char sTab[] = { "kot" }

k  o  t  NULL 

 

Na  liście  inicjalizacyjnej  znajduje  się  łańcuch  znakowy,  więc  kompilator 

automatycznie doda znak NULL. 
 
W  powyŜszy  sposób  moŜna  jedynie  inicjalizować  tablice.  Nie  moŜna  wykonywać  operacji 
przypisania. 
 

background image

Krzysztof Karbowski: Programowanie w języku C++ 

31 

Przykład 

: 

Temat: Funkcja kopiująca łańcuchy znakowe. 

#include <iostream> 
using namespace std; 
void kopiuj(char cel[], char zrodlo[]); 
void wypisz(char tab[]); 
//---------------------------- 
int main() 

char sTab1[] = { "kot"}; 
char sTab2[10]; 
 

cout << "sTab1="; 

 

wypisz(sTab1); 

 

kopiuj(sTab2,sTab1); 

 

cout << "sTab2="; 

 

wypisz(sTab2); 

return 0; 

//------------------------------ 
void kopiuj(char cel[], char zrodlo[]) 

int i; 
 

for (i=0; ; i++) 

 

 

  cel[i]=zrodlo[i]; 

 

  if (zrodlo[i]==NULL) break

 


//------------------------------ 
void wypisz(char tab[]) 

int i; 
 

for (i=0; ; i++) 

 

  if (tab[i]==NULL) break

 

  else cout << tab[i]; 

 

cout << endl; 

 
Przykład 

: 

Temat: Program wykorzystujący funkcję biblioteczną kopiująca łańcuchy znakowe. 

#include <iostream> 
#include <string> 
using namespace std; 
void wypisz(char tab[])
//---------------------------- 
int main() 
{ 
char sTab1[] = { "kot"}
char sTab2[10]
 

cout << "sTab1="

 

wypisz(sTab1)

 

strcpy(sTab2,sTab1)

 

cout << "sTab2="

 

wypisz(sTab2)

 

return 0; 

background image

Krzysztof Karbowski: Programowanie w języku C++ 

32 

} 
//---------------------------- 
void wypisz(char tab[i]) // taka jak w poprzednim programie 

8.5. Tablice wielowymiarowe 

Są to tablice, których elementami są inne tablice. 
 

int Tab[4][2];  // tablica czterech elementów, z których  
 

   

 

// ka

Ŝ

dy jest dwuelementow

ą

 tablic

ą

  

 

   

 

// obiektów typu int 

Uwaga:  zapis 

Tab[i,j]

  zostanie  zinterpretowany  jako 

Tab[j]

  (występuje  operator 

"przecinek"). 

8.5.1. Inicjalizacja tablic wielowymiarowych: 

int Tab1[3][2] = { 11, 12, 21, 22, 31, 32 }
int Tab2[3][2] = { {11, 12}{21, 22}{31, 32} }
 
Element  Tab1[1,1]  jest  przesunięty  w  stosunku  do  początku  tablicy  o 

(1*2)+1

  elementów, 

czyli 

numer_wiersza*ilo

ść

_kolumn+numer_kolumny

  –  aby  obliczyć  jego  połoŜenie 

musi  być  znana  liczba  kolumn  tablicy  (drugi  wymiar)  –  nie  jest  konieczna  znajomość  ilości 
wierszy (pierwszy wymiar). 
 

 

11 

12 

21 

22 

31 

32 

8.5.2. Przesyłanie tablic wielowymiarowych do funkcji 

Aby funkcja mogła obliczyć, gdzie w pamięci znajduje się określony element tablicy – musi 
znać liczbę kolumn tablicy. 
 

void funkcja1(float tab[][4]);// funkcja musi zna

ć

 liczb

ę

 

 

   

 

 

        //  kolumn 

void funkcja2(float tab[][3][5]);  //   aby obliczy

ć

 poło

Ŝ

enie  

                                   //     elementu 
// void funkcja3( float tab[][][]) tak jest 

ź

le 

 

9. Wska

ź

niki 

Wskaźnik  to  obiekt  do  przechowywania  informacji  o  adresie  i  typie 
innego obiektu. 

9.1. Definiowanie wska

ź

ników 

int * w ;   

// w jest wska

ź

nikiem do obiektów typu int 

char * pLancuch; 

// pLancuch jest wskaznikiem do obiektow typu char 

float * pWsk; 

// pWsk jest wskaznikiem do obiektow typu float 

 
Zastosowanie wskaźników: 

 

ulepszenie pracy z tablicami, 

 

funkcje mogące zmieniać wartość przysyłanych do nich argumentów, 

background image

Krzysztof Karbowski: Programowanie w języku C++ 

33 

 

dostęp do specjalnych komórek pamięci, 

 

rezerwacja obszarów pamięci. 

9.2. Praca ze wska

ź

nikiem 

Przykład 

: 

#include <iostream> 
using namespace std; 
//---------------------------- 
int main() 

int nLiczba=5; 
int nLiczba2=10; 
int *pInt; 
int *pInt2; 
int *pInt3; 
float Liczba3=1.2; 
float *pFloat; 
void *pWsk; 
 

 

 

cout << "nLiczba=" << nLiczba << endl; // pojawi sie 5 

 

pInt = &nLiczba;  // ustawienie wskaznika 

 

cout << "pInt=" << pInt << endl; // pojawi sie adres 

 

cout << "(*pInt)=" << *pInt << endl; // pojawi sie 5 

 

cout << "Przypisanie *pInt=6\n" ; 

 

*pInt = 6 ; 

 

cout << "(*pInt)=" << *pInt << endl; // pojawi sie 6 

 

cout << "nLiczba=" << nLiczba << endl; // pojawi sie 6 

 

cout << "zmiana obiektu wskazywanego\n" ; 

 

pInt = &nLiczba2; 

 

cout << "nLiczba2=" << nLiczba2 << endl; // pojawi sie 10 

 

cout << "(*pInt)=" << *pInt << endl; // pojawi sie 10 

 

// -------------------------------- 

 

pFloat = &Liczba3; 

 

cout << "(*pFloat)=" << *pFloat << endl; // pojawi sie 1.2 

 

// -------------------------------- 

 

// pFloat=pInt; // <<< - zostanie zasygnalizowany blad 

 

pWsk = pInt; 

 

cout << "pWsk=" << pWsk << endl; // pojawi sie adres  

 

// cout << *pWsk; // <<< - blad 

 

pInt2 = (int*)pWsk;  // musi byc rzutowanie 

 

cout << "(*pInt2)=" << *pInt2 << endl; // pojawi sie 10 

 
 

pFloat = (float*)pInt; // musi byc rzutowanie 

 

cout << "(*pFloat)=" << *pFloat << endl; // pojawi sie  

 

   

// przypadkowa liczba mimo prawidlowego adresu 

 

pInt3 = (int*)pFloat; // musi byc rzutowanie 

 

cout << "(*pInt3)=" << *pInt3 << endl; // pojawi sie 10 

return 0; 

 

Wskaźnik  do  obiektu  kaŜdego  niestałego  typu  moŜna  przypisać 
wskaźnikowi typu void. 

background image

Krzysztof Karbowski: Programowanie w języku C++ 

34 

9.3. Zastosowanie wska

ź

ników wobec tablic 

Przykład: 

int *wsk1, *wsk2; 
int tab1[3]={11, 12, 13 }
int tab2[3]={21, 22, 23 }
wsk1 = &tab1[0]
wsk2 = tab2;  // nazwa tablicy jest adresem jej pierwszego 
 

   

 

// elementu 

wsk1 = &tab1[2]// wskaznik pokazuje na ostatni element 
 

   

 

  // tablicy 

wsk2 = wsk2 + 1; // wskaznik pokazuje na drugi element 
 

   

 

 // tablicy 

 

Dodanie  do  wskaźnika  liczby  całkowitej  powoduje,  Ŝe  pokazuje  on 
o tyle  dalszy  element  tablicy  niezaleŜnie  od  tego  jakiego  typu  są  to 
elementy  (niezaleŜnie  od  ilości  pamięci  przeznaczonej  na  kaŜdy 
element).  

 
Przykład 

: 

#include <iostream> 
using namespace std; 
int main() 
{ 
int *wsk1, *wsk2; 
int tab[10]
int i; 
 

 

 

wsk1=tab; 

 

for (i=0; i<10; i++) 

 

  *(wsk1+i)=i*10; 

 

cout << "Elementy tablicy:\n"

 

for (i=0; i<10; i++) 

 

  cout << i << ": " << *(wsk1+i) << endl; 

 

cout << endl; 

 

wsk2 = &tab[3]

 

cout << "3: " << *wsk2 << endl; 

 

wsk2 += 2; 

 

cout << "(3+2): " << *wsk2 << endl; 

 

return 0; 

} 

9.4. Działania na wska

ź

nikach 

(wskaźnik + liczba_całkowita) – przesunięcie wskaźnika o podaną liczbę elementów w przód, 
(wskaźnik – liczba_całkowita) – przesunięcie wskaźnika o podaną liczbę elementów w tył, 
(wskaźnik – wskaźnik) –  gdy wskaźniki pokazują na elementy tej samej tablicy to wynikiem 

będzie liczba dzielących je elementów (liczba dodatnia lub ujemna). 

9.5. Porównywanie wska

ź

ników 

operator 

==

   

równość wskaźników oznacza, Ŝe pokazują na ten sam obiekt, 

operator 

!=

 

przeciwieństwo operatora 

==

 
Operatory mające zastosowanie do wskaźników pokazujących na elementy tej samej tablicy: 

background image

Krzysztof Karbowski: Programowanie w języku C++ 

35 

>    <    >=    <= 

9.6. Zastosowanie wska

ź

ników w argumentach funkcji 

Przykład 

: 

#include <iostream> 
using namespace std; 
void zmien(int *wsk)
//--------------------- 
int main() 
{ 
int liczba=1; 
 

cout << "Przed wywolaniem funkcji: " << liczba << endl; 

 

zmien(&liczba)

 

cout << "Po wywolaniu funkcji: " << liczba << endl; 

 

return 0; 

} 
//--------------------- 
void zmien(int *wsk) 
{ 
 

*wsk=100; 

} 

9.6.1. Odbieranie tablicy jako wska

ź

nika 

Przykład 

: 

#include <iostream> 
using namespace std; 
void fkc_tab(int tab[], int rozmiar); 
void fkc_wsk1(int *wsk, int rozmiar); 
void fkc_wsk2(int *wsk, int rozmiar); 
//--------------------- 
int main() 

int tablica[4] = { 1, 2, 3, 4 }; 
 

fkc_tab(tablica,4); 

 

fkc_wsk1(tablica,4); 

 

fkc_wsk2(tablica,4); 

 

cout << endl; 

return 0; 

//--------------------- 
void fkc_tab(int tab[], int rozmiar) 

 

cout << "\nPrzeslano jako tablice\n" ; 

 

for (int i=0; i<rozmiar; i++) 

 

  cout << tab[i] << "\t"; 


//--------------------- 
void fkc_wsk1(int *wsk, int rozmiar) 

 

cout << "\nPrzeslano jako wskaznik - wariant 1\n" ; 

 

for (int i=0; i<rozmiar; i++) 

 

  cout << *(wsk+i) << "\t"; 


//--------------------- 
void fkc_wsk2(int *wsk, int rozmiar) 

background image

Krzysztof Karbowski: Programowanie w języku C++ 

36 


 

cout << "\nPrzeslano jako wskaznik - wariant 2\n" ; 

 

for (int i=0; i<rozmiar; i++) 

 

  cout << wsk[i] << "\t"; 

9.6.2. Argument formalny b

ę

d

ą

cy wska

ź

nikiem do obiektu const 

Przykład: 

 

void funkcja(const int *wsk, int rozmiar)

 
Wskaźnik const pokazuje na obiekty, ale nie pozwala na ich modyfikacje. 
Zastosowanie: 

1.

 

Zagwarantowanie,  Ŝe  obiekt  wysłany  do  funkcji  poprzez  wskaźnik  nie  zostanie 
zmieniony, 

2.

 

UmoŜliwienie wysłania do funkcji poprzez wskaźnik obiektu stałego (moŜna na niego 
pokazać tylko wskaźnikiem do stałej). 

9.7.  Zastosowanie  wska

ź

ników  przy  dost

ę

pie  do  konkretnych 

komórek pami

ę

ci 

Przykład: 

 

wsk = 0x0065fde8; 

 
Wskaźnikowi  naleŜy  przypisać  adres  komórki  pamięci  (sposób  adresowania  zaleŜny  jest  od 
architektury komputera, systemu operacyjnego i kompilatora). 

9.8. Rezerwacja obszarów pami

ę

ci 

9.8.1. Operatory new i delete 

Przykład: 

int *wsk; 
wsk = new int; 
// ........... 
delete wsk; 

Operator 

new

  utworzy  nowy  obiekt  typu 

int

,  który  nie  będzie  miał  nazwy,  a  jego  adres 

zostanie  przekazany  do  wskaźnika 

wsk

.  Operator 

delete

  zlikwiduje  obiekt  pokazywany 

przez wskaźnik 

wsk

Dynamiczne tworzenie tablic: 

float *wsk; 
int rozmiar; 
cout << “Podaj rozmiar tablicy: “; cin >> rozmiar; 
wsk = new float[rozmiar]
//.... 
delete [] wsk; 

Wstępna inicjalizacja obiektu: 

int *wsk; 
wsk = new int(12)

Alokacja obiektu w konkretnym miejscu pamięci: 

 

wsk = 0x0065fde8; 
wsk2 = wsk new int; 

 
Cechy obiektów utworzonych operatorem 

new

background image

Krzysztof Karbowski: Programowanie w języku C++ 

37 

 

obiekty te nie mają nazwy – dostęp do nich odbywa się poprzez wskaźnik, 

 

początkowe  wartości  obiektów  są  przypadkowe,  chyba  Ŝe  zostały  wstępnie 
zainicjalizowane, 

 

czas  Ŝycia:  od  chwili  utworzenia  operatorem 

new

  do  momentu  usunięcia  operatorem 

delete

 

zakres  waŜności:  jeśli  w  danym  momencie  jest  przynajmniej  jeden  wskaźnik  pokazujący 
na obiekt, to jest do niego dostęp. 

Przykład 

 : 

#include <iostream> 
using namespace std; 
int main() 
{ 
int *wsk1, *wsk2; 
int i, rozmiar; 
 

cout << "Podaj rozmiar tablicy: "

 

cin >> rozmiar; 

 

wsk1 = new int[rozmiar]

 

if (wsk1==NULL) 

 

  cout << "Brak pamieci\n"

 

else 

 

{ 

 

  for (i=0; i<rozmiar; i++) 

 

   

wsk1[i]=i*10; 

 

  cout << "Tablica:\n"

 

  for (i=0; i<rozmiar; i++) 

 

   

cout << i << ": " << wsk1[i] << endl; 

 

  wsk2 = new int; 

 

  *wsk2=10; 

 

  cout << "*wsk2 = " << *wsk2 << endl; 

 

  wsk2=wsk1; // utrata dostepu do obiektu 

 

  delete [] wsk1; 

 

  wsk1=NULL; 

 

  //delete wsk2; // niebezpieczenstwo zalamania programu 

 

return 0; 
} 

 

Wskaźniki  definiowane  z  modyfikatorem 

static

  inicjalizowane  są 

wartością 

NULL

.  Pozostałe  wskaźniki  mają  wartości  przypadkowe,  a 

więc wskazują na przypadkowe obszary pamięci. Próba zapisu takiego 
miejsca moŜe spowodować załamanie programu. 

 

9.9. Sposoby inicjalizowania wska

ź

ników 

 
wsk = & obiekt; 
 
wsk = inny_wskaznik; 
 
wsk = tablica; 
 
wsk = funkcja; 
 

background image

Krzysztof Karbowski: Programowanie w języku C++ 

38 

wsk = new int
 
wsk = new float[10]
 
wsk = 0x82a5f2;  // adres 
 
wsk = "lancuch tekstowy"

9.10. Tablice wska

ź

ników 

Przykład – pięcioelementowa tablica wskaźników do obiektów typu 

float

 
 

float *tabwsk[5]// inaczej: float *(tabwsk[5])

 

Przykład – tablice wskaźników do stringów: 

 
 

char *tab1[3]

 

char *tab2[3] = { "jeden", "dwa", "trzy" }

 

W  tablicy 

tab2

  znajdują  się  wskaźniki  do  miejsc  w  pamięci,  w  których  zlokalizowane  są 

poszczególne łańcuchy tekstowe. 
 
Przykład 

 : 

#include <iostream> 
using namespace std; 
char* dopisz_spacje(const char *wsk1, char *wsk2); 
char* dopisz_spacje2(const char *wsk1, char **wsk2); 
void kody(const char *wsk, int rozmiar); 
//-------------------- 
int main() 

char tab1[] = { "tablica1" }; 
char tab2[20] = { 't','a','b','l','i','c','a','2' }; 
char tab3[] = { 't','a','b','l','i','c','a','3','\0' }; 
char *wsk1 = "wskaznik1"; 
char *wsk2 = { "wskaznik2" }; 
char *wsk=NULL; 
 
 

cout << "tab1: " << tab1 << endl; 

 

wsk = new char[80]; 

 

cout << "t a b 1 : " << dopisz_spacje(tab1,wsk) << endl; 

 

delete [] wsk; 

 

wsk=NULL; 

 

cout << "t a b 1 (wersja 2): " << dopisz_spacje2(tab1,&wsk) 

 

   

 

 << endl; 

 

delete [] wsk; 

 

cout << "tab2: ";  

kody(tab2,20); 

 

cout << "tab3: " << tab3 << endl; 

 

cout << "wsk1: " << wsk1 << endl; 

 

cout << "wsk2: " << wsk2 << endl; 

return 0; 

//-------------------- 
char* dopisz_spacje(const char *wsk1, char *wsk2) 

background image

Krzysztof Karbowski: Programowanie w języku C++ 

39 

int ile_znakow, i; 
 

 

 

for (ile_znakow=0; *(wsk1+ile_znakow)!=NULL; ile_znakow++) 

 

  /* */; 

 

for (i=0; i<ile_znakow; i++) 

 

 

  wsk2[2*i] = wsk1[i]; 

 

  wsk2[2*i+1] = ' '; 

 

 

wsk2[2*ile_znakow]=NULL; 

 

return wsk2; 


//------------------------ 
char* dopisz_spacje2(const char *wsk1, char **wsk2) 

int ile_znakow, i; 
 

 

 

for (ile_znakow=0; *(wsk1+ile_znakow)!=NULL; ile_znakow++) 

 

  /* */; 

 

*wsk2 = new char[2*ile_znakow+1]; 

 

for (i=0; i<ile_znakow; i++) 

 

 

  (*wsk2)[2*i] = wsk1[i]; 

 

  (*wsk2)[2*i+1] = ' '; 

 

 

(*wsk2)[2*ile_znakow]=NULL; 

 

return *wsk2; 


//---------------------- 
void kody(const char *wsk, int rozmiar) 

int i; 
 

for (i=0; i<rozmiar; i++) 

 

  cout << int(*(wsk+i)) << ','; 

 

cout << endl; 

9.11. Wska

ź

niki do funkcji 

Definicja: 
 

int (*wsk_do_funkcji)(int, char)

 
oznacza,  Ŝe 

wsk_do_funkcji

  jest  wskaźnikiem  do  funkcji  wywoływanej  z  parametrami 

typu 

int

 i 

char

 oraz zwracającej wartość typu 

int

 

Nazwa funkcji jest jednocześnie adresem jej początku. 

 
Przykład 

: 

 

#include <iostream> 
using namespace std; 
int dodaj_dwa(int a); 
int dodaj_trzy(int a); 
int wywolaj(int (*wsk)(int), int liczba); 

background image

Krzysztof Karbowski: Programowanie w języku C++ 

40 

//---------------------- 
int main() 

int a=10; 
int (*wsk_fkc)(int parametr); 
int (*tab_wsk_fkc[2])(int); // tablica wskaznikow do funkcji 
 
 

cout << "dodaj_dwa: " << dodaj_dwa(a) << endl; 

 

cout << "dodaj_trzy: " << dodaj_trzy(a) << endl; 

 

wsk_fkc=dodaj_dwa; 

 

cout << "wsk. do dodaj_dwa: " << (*wsk_fkc)(a) << endl; 

 

wsk_fkc=dodaj_trzy; 

 

cout << "wsk. do dodaj_trzy: " << (*wsk_fkc)(a) << endl; 

 

cout << "f(dodaj_trzy): " << wywolaj(dodaj_trzy,a) << endl; 

 

tab_wsk_fkc[0]=dodaj_dwa; 

 

tab_wsk_fkc[1]=dodaj_trzy; 

 

cout << "tablica ze wsk. do dodaj_trzy: "  

 

  << (*tab_wsk_fkc[1])(a) << endl; 

return 0; 

//------------------------ 
int dodaj_dwa(int a) 
{  return a+2; } 
//------------------------ 
int dodaj_trzy(int a) 
{   return a+3; } 
//------------------------ 
int wywolaj(int (*wsk)(int), int liczba) 
{  return (*wsk)(liczba); } 
 

___________________________________________________________________________ 

10. Przeładowanie nazw funkcji 

Przeładowanie  nazwy  funkcji  polega  na  tym,  Ŝe  w  danym  zakresie  waŜności  jest  więcej  niŜ 
jedna funkcja o tej samej nazwie. Poszczególne funkcje róŜnią się typami argumentami. 
 
Przykład 

: 

#include <iostream> 
using namespace std; 
void drukuj(int)
void drukuj(float)
void drukuj(char)
void drukuj(int, float)
void drukuj(float, int)
//----------------- 
int main() 
{ 
int a = 10; 
float b = 12.6; 
char c = a
 
 

drukuj(a)

 

drukuj(b)

 

drukuj(c)

background image

Krzysztof Karbowski: Programowanie w języku C++ 

41 

 

drukuj(a,b)

 

drukuj(b,a)

return 0; 
} 
//----------------- 
void drukuj(int a) 
{ cout << a << endl; } 
//----------------- 
void drukuj(float a) 
{ cout << a << endl; } 
//----------------- 
void drukuj(char a) 
{ cout << a << endl; } 
//------------------ 
void drukuj(int a, float b) 
{ cout << a << "   " << b << endl; } 
//------------------ 
void drukuj(float b, int a) 
{ cout << a << "   " << b << endl; } 

 
Przykład – poniŜszych funkcji nie moŜna przeładować: 

 
void funkcja(int tab[])
void funkcja(int *wsk)

10.1. Wska

ź

nik do funkcji przeładowanej 

Przykład: 

int funkcja(int)
int funkcja(float)
//------------ 
int (*wsk_do_fkc)(int)
wsk_do_fkc = funkcja; // do wskaznika zostanie przypisany adres 
 

// funkcji "funkcja(int)" – wynika to z definicji wskaznika 

 

11. Klasy 

Definicja klasy: 

class nazwa_klasy 
{ 
 

// cialo klasy 

 

// .............. 

} ; 

  // <<- srednik 

 

Definicja obiektu danej klasy (typu zdefiniowanego przez uŜytkownika): 

 
nazwa_klasy zmienna; 
 

Definicja wskaźnika i referencji do obiektu danej klasy: 

 
nazwa_klasy * wsk ; 
nazwa_klasy & refer = zmienna; 

background image

Krzysztof Karbowski: Programowanie w języku C++ 

42 

11.1. Składniki klasy 

Dostęp do składników klasy: 

 

obiekt.składnik 

 

wskaźnik 

->

 składnik 

 

referencja.składnik 

 
Przykład 

: 

#include <iostream> 
#include <string> 
using namespace std; 
//--------------------- 
class COsoba 

public: 
 

char m_sImie[80]; 

 

char m_sNazwisko[80]; 

 

int m_nWaga; 

 

int m_nWzrost; 

}; 
//--------------------- 
int main() 

COsoba Kowalski; 
COsoba &rOsoba = Kowalski; // referencja (musi byc  
 

   

 

   //  

 

zainicjalizowana) 

COsoba *pOsoba; // wskaznik 
 
 

strcpy(Kowalski.m_sImie, "Jan"); 

 

strcpy(Kowalski.m_sNazwisko, "Kowalski"); 

 

Kowalski.m_nWaga = 65; 

 

Kowalski.m_nWzrost = 178; 

 

pOsoba = & Kowalski; 

 
 

cout << Kowalski.m_sImie << " " << Kowalski.m_sNazwisko  

 

   

<< endl; 

 

cout << "waga: " << pOsoba->m_nWaga << endl; 

 

cout << "wzrost: " << rOsoba.m_nWzrost << endl; 

return 0; 

11.2. Funkcje składowe klasy 

Definicja funkcji składowej klasy jako funkcji typu 

inline

class nazwa_klasy 
{ 
 

// ............ 

 

typ nazwa_funkcji(lista_parametrow) 

 

  { 

 

  // cialo funkcji 

 

  } 

}

Deklaracja i definicja funkcji składowej klasy: 

class nazwa_klasy 
{ 

background image

Krzysztof Karbowski: Programowanie w języku C++ 

43 

 

// ............ 

 

typ nazwa_funkcji(lista_parametrow)

}
typ nazwa_klasy :: nazwa_funkcji(lista_parametrow) 
{ 
 

// cialo funkcji 

} 

 
Przykład 

: 

#include <iostream> 
#include <string> 
using namespace std; 
//--------------------- 
class COsoba 

public: 
 

char m_sImie[80]; 

 

char m_sNazwisko[80]; 

 

int m_nWaga; 

 

int m_nWzrost; 

 

void WstawDane(char *imie, char *nazwisko,  

 

   

 

 

int waga, int wzrost); 

 

void WydrukujDane(); 

}; 
void COsoba::WstawDane(char *imie, char *nazwisko,  
 

   

 

 

   int waga, int wzrost) 


 

strcpy(m_sImie, imie); 

 

strcpy(m_sNazwisko, nazwisko); 

 

m_nWaga = waga; 

 

m_nWzrost = wzrost; 


void COsoba::WydrukujDane() 

 

cout << m_sImie << " " << m_sNazwisko << endl; 

 

cout << "waga: " << m_nWaga << endl; 

 

cout << "wzrost: " << m_nWzrost << endl; 


//--------------------- 
int main() 

COsoba Kowalski; 
COsoba *pOsoba;  
 
 

Kowalski.WstawDane("Jan","Kowalski",65,178); 

 

pOsoba = & Kowalski; 

 

pOsoba->WydrukujDane(); 

return 0; 

11.3. Rodzaje dost

ę

pu do składników klasy 

Rodzaje dostępu do składników (zmiennych i funkcji) klasy: 

 

private

 – składniki dostępne są wyłącznie dla składników klasy, 

 

public

 – składniki są dostępne bez ograniczeń. 

background image

Krzysztof Karbowski: Programowanie w języku C++ 

44 

Przykład: 

class nazwa_klasy 
{ 
// skladniki prywatne  
private: 
 

// deklaracje/definicje składników 

// ---------------------- 
// składniki publiczne 
public: 
 

// deklaracje/definicje składników 

}

Dopóki w definicji klasy nie wystąpi Ŝadna etykieta to składniki mają dostęp 

private

11.4. Obiekty b

ę

d

ą

ce składnikami klasy 

Przykład klasy zawierającej obiekt innej klasy: 

class zarowka 
{ 
public: 
 

int moc; 

 

double srednica; 

 

void zaswiec()

 

void zgas()

}
class lampa 
{ 
public: 
 

int wysokosc; 

 

zarowka punkt_swietlny1; 

 

zarowka punkt_swietlny2; 

 

void zaswiec()

 

void zgas()

}

11.5. Przesyłanie do funkcji argumentów b

ę

d

ą

cych obiektami 

Przykład 

: 

#include <iostream> 
#include <string> 
using namespace std; 
//--------------------- 
class COsoba 

public: 
 

char m_sImie[80]; 

 

char m_sNazwisko[80]; 

 

int m_nWaga; 

 

int m_nWzrost; 

 

void WstawDane(char *imie, char *nazwisko,  

 

   

 

 

int waga, int wzrost); 

}; 
void COsoba::WstawDane(char *imie, char *nazwisko,  
 

   

 

 

   int waga, int wzrost) 


 

strcpy(m_sImie, imie); 

 

strcpy(m_sNazwisko, nazwisko); 

background image

Krzysztof Karbowski: Programowanie w języku C++ 

45 

 

m_nWaga = waga; 

 

m_nWzrost = wzrost; 


//--------------------- 
void wydrukuj_dane(COsoba osoba); 
void wydrukuj_nazwisko(COsoba & osoba); 
//---------------------- 
int main() 

COsoba Kowalski; 
 
 

Kowalski.WstawDane("Jan","Kowalski",65,178); 

 

wydrukuj_dane(Kowalski); 

 

wydrukuj_nazwisko(Kowalski); 

return 0; 

//--------------------- 
void wydrukuj_dane(COsoba osoba) 
// przekazanie obiektu przez wartosc 

 

cout << osoba.m_sImie << " " << osoba.m_sNazwisko << endl; 

 

cout << "waga: " << osoba.m_nWaga << endl; 

 

cout << "wzrost: " << osoba.m_nWzrost << endl; 


//---------------------- 
void wydrukuj_nazwisko(COsoba & osoba) 
// przekazanie obiektu przez referencje 

 

cout << "Nazwisko: " << osoba.m_sNazwisko << endl; 

11.6. Składnik statyczny 

class nazwa_klasy 
{ 
// cialo klasy 
 

static typ1 nazwa1; 

// deklaracja składnika statycznego 

 

static typ2 nazwa2; 

// ........... 
}
typ1 nazwa_klasy::nazwa1;  // definicja składnika statycznego 
typ2 nazwa_klasy::nazwa2 = wartosc; // definicja  
 

   

 

 

 

// i inicjalizacja składnika stat. 

 
Cechy składnika statycznego: 

 

miejsce  w  pamięci  dla  składnika  statycznego  jest  przydzielane  tylko  raz, 
niezaleŜnie  od  ilości  obiektów  danej  klasy  –  składnik  statyczny  jest  wspólny  dla 
wszystkich obiektów klasy, 

 

składnik statyczny istnieje nawet wtedy gdy nie ma Ŝadnego obiektu danej klasy, 

 

dostęp do składnika statycznego: 

nazwa_klasy::nazwa_skladnika 

 

dostęp do składnika statycznego gdy istnieją obiekty danej klasy: 

obiekt.nazwa_skladnika 
wskaznik->nazwa_skladnika 

background image

Krzysztof Karbowski: Programowanie w języku C++ 

46 

11.7. Statyczna funkcja składowa 

class nazwa_klasy 
{ 
// ciało klasy 
 

static typ nazwa_funkcji(parametry)// deklaracja funkcji 

// ... 
}

Cechy statycznej funkcji składowej: 

 

funkcję moŜna wywołać gdy nie istnieje Ŝaden obiekt danej klasy, 

 

wewnątrz funkcji nie ma wskaźnika 

this

 

funkcja nie ma moŜliwości odwoływania się do niestatycznych składników klasy, 

 

sposoby wywołania funkcji: takie jak dostęp do składnika statycznego. 

 
Przykład 

: 

#include <iostream> 
using namespace std; 
class klasa 

public: 
 

int numer; 

 

static long licznik; 

 

static void zerujlicznik(){ licznik=0; } 

}; 
long klasa::licznik = 0; 
//--------- 
int main() 

 

cout << "licznik=" << klasa::licznik << endl; 

 

klasa obiekt1; 

 

obiekt1.licznik++; 

 

cout << "licznik=" << klasa::licznik << endl; 

 

klasa obiekt2; 

 

obiekt2.licznik++; 

 

cout << "licznik=" << klasa::licznik << endl; 

 

klasa::zerujlicznik(); 

 

cout << "licznik=" << klasa::licznik << endl; 

return 0; 

11.8. Funkcje składowe typu const 

class nazwa_klasy 
{ 
// ciało klasy 
 

typ nazwa_funkcji(parametry) const

// ............ 
}
typ nazwa_klasy::nazwa_funkcji(parametry) const 
{ 
 

// ciało funkcji 

} 

Są to funkcje deklarujące, Ŝe nie będą zmieniały obiektu, na rzecz którego pracują.  
SłuŜą do pracy z obiektami zdefiniowanymi jako 

const

background image

Krzysztof Karbowski: Programowanie w języku C++ 

47 

12. Funkcje zaprzyja

ź

nione 

Są to funkcje, które mają dostęp do składników prywatnych danej klasy. 

class nazwa_klasy 
{ 
 

friend typ nazwa_funkcji(parametry)

// cialo klasy 
}
typ nazwa_funkcji(parametry) 
{ 
 

// cialo funkcji 

} 

Funkcje  te  nie  posiadają  wskaźnika 

this

  do  składników  klasy,  z  którą  są  zaprzyjaźnione,  a 

więc muszą posługiwać się operatorami 

.

 (kropka) lub 

->

 
Przykład 

: 

#include <iostream> 
using namespace std; 
class klasa 

 

friend int przyjaciel(klasa ob); 

private: 
 

int liczba; 

public: 
 

void ustaw(int wartosc) { liczba=wartosc; } 

 

void wyswietl() { cout << "liczba=" << liczba << endl; } 

}; 
//--------------- 
int przyjaciel(klasa ob) 

 

return ob.liczba; 


//--------------- 
int main() 

klasa objekt; 
 

 

 

objekt.ustaw(10); 

 

objekt.wyswietl(); 

 

cout << "Przyjaciel: liczba=" << przyjaciel(objekt) << endl; 

return 0; 

 

13. Struktury, unie i pola bitowe 

13.1. Struktura 

Struktura to klasa, w której wszystkie składniki są publiczne. Składnikami struktur nie mogą 
być funkcje. 

struct nazwa_struktury 
{ 
// lista składnikow 
}

background image

Krzysztof Karbowski: Programowanie w języku C++ 

48 

13.2. Unia 

Unia to struktura, w której poszczególne składniki zajmują to samo miejsce w pamięci. 
Przykład: 

union pojemnik 
{ 
 

char c; 

 

int i; 

 

float f; 

}

13.3. Pole bitowe 

Pole bitowe to typ składnika klasy polegający na tym, Ŝe informacja jest przechowywana na 
określonej liczbie bitów. 
Przykład: 

class klasa 
{ 
public: 
 

unsigned int bit1 : 1; 

 

unsigned int bit4 : 4; 

}

 

14. Konstruktory i destruktory 

14.1. Konstruktor 

Konstruktor to funkcja składowa klasy postaci 

nazwa_klasy(parametry)

która jest automatycznie wywoływana podczas definiowania obiektu danej klasy. 
Cechy konstruktora: 

 

konstruktor moŜe być przeładowywany, 

 

konstruktor nie ma wyspecyfikowanego typu wartości zwracanej, 

 

konstruktor nie zwraca Ŝadnej wartości (nawet 

void

), 

 

konstruktor  moŜe  być  wywoływany  dla  tworzenia  obiektów  z  modyfikatorem 

const

, ale sam nie moŜe być funkcją typu 

const

 

konstruktor nie moŜe być typu 

static

 

nie moŜna posłuŜyć się adresem konstruktora. 

14.2. Kiedy wywoływany jest konstruktor 

14.2.1. Konstruowanie obiektów lokalnych 

Obiekty  lokalne  automatyczne  –  konstruktor  uruchamiany  jest  w  momencie,  gdy  program 

napotyka definicję obiektu. 

Obiekty  lokalne  statyczne  –  konstruktor  zostanie  uruchomiony  w  momencie  uruchomienia 

programu. 

14.2.2. Konstruowanie obiektów globalnych 

Konstruktor zostanie uruchomiony w momencie uruchomienia programu. 

background image

Krzysztof Karbowski: Programowanie w języku C++ 

49 

14.2.3. Konstrukcja obiektów tworzonych operatorem new 

Konstruktor  zostanie  uruchomiony  po  wywołaniu  operatora 

new

.  Konstruktor  nie  przydziela 

miejsca w pamięci dla tworzonego obiektu – jedynie inicjalizuje wartości składników. 

14.2.3. Inne przypadki uruchamiania konstruktora 

Konstruktor wywoływany jest podczas tworzenia obiektów chwilowych swojej klasy. 
Konstruktor  jest  wywoływany  jeśli  jest  tworzony  obiekt  jakiejś  klasy,  który  zawiera  obiekt 

klasy tego konstruktora. 

14.3. Destruktor 

Destruktor to funkcja składowa klasy postaci 

~nazwa_klasy()

która jest automatycznie wywoływana podczas likwidowania obiektu danej klasy. 
Cechy destruktora: 

 

destruktor nie moŜe zwracać Ŝadnej wartości (nawet 

void

), 

 

destruktor jest wywoływany bez jakichkolwiek argumentów, 

 

destruktor nie moŜe być przeładowany, 

 

nie moŜna pobrać adresu destruktora, 

 

destruktor  nie  moŜe  być  funkcją  typu 

const

,  ale  moŜe  pracować  na  rzecz 

obiektów typu 

const

 
Przykład 

: 

#include <iostream> 
#include <string> 
using namespace std; 
//------------------- 
class napis 

private: 
 

char tekst[80]; 

 

char przypis[80]; 

 

int x; 

 

int y; 

public: 
 

napis(); 

 

napis(char *t, char *p, int wspx=0, int wspy=0); 

 

~napis(); 

 

void wyswietl(); 

}; 
//------- 
napis::napis() 

 

strcpy(tekst,"BRAK"); 

 

strcpy(przypis,"BRAK"); 

 

x=0; y=0; 

 

wyswietl(); 


//-------- 
napis::napis(char *t, char *p, int wspx, int wspy) 

 

strcpy(tekst,t); 

 

strcpy(przypis,p); 

background image

Krzysztof Karbowski: Programowanie w języku C++ 

50 

 

x=wspx; 

 

y=wspy; 

 

wyswietl(); 


//--------- 
napis::~napis() 

 

cout << "destruktor: " << tekst << endl; 


//--------- 
void napis::wyswietl() 

 

cout << "\n------------------\n"; 

 

cout << "tekst: " << tekst << endl; 

 

cout << "przypis: " << przypis << endl; 

 

cout << "x=" << x << "   y=" << y << endl; 

 

cout << "\n------------------\n"; 


//------------------------------------ 
int main() 

 

napis Tekst1("Tekst1","Przypis1",10,10); 

 

napis Tekst2; 

 

napis Tekst3("Tekst3","Przypis3"); 

 

napis Tekst4 = napis("Tekst4","Przypis4",1,2); 

 

napis *wsk; 

 

wsk = new napis("Wskaznik","Przypis",5,3); 

 

delete wsk; 

return 0; 

14.4. Konstruktor domniemany 

Konstruktor domniemany ta taki konstruktor, który moŜna wywołać bez Ŝadnego argumentu. 
Przykład: 

class klasa1 
{ 
//........... 
public: 
 

klasa1(int a)

 

klasa1()

// konstruktor domniemany 

 

klasa1(float b)

//......... 
}
class klasa2 
{ 
//........... 
public: 
 

klasa2(int a)

 

klasa2(float b)

 

klasa2(int a=1; double b=3.1)// konstruktor domniemany 

//............ 
}

 
Jeśli  klasa  nie  ma  Ŝadnego  konstruktora,  to  kompilator  sam  wygeneruje  dla  tej  klasy 
konstruktor domniemany. 

background image

Krzysztof Karbowski: Programowanie w języku C++ 

51 

14.5. Lista inicjalizacyjna konstruktora 

Definicja konstruktora z listą inicjalizacyjną: 

nazwa_klasy::nazwa_klasy(parametry) : lista_inicjalizacyjna 
{ 
 

// ciało konstruktora 

} 

Etapy wykonania konstruktora: 

1.

 

inicjalizacja składników z listy inicjalizacyjnej konstruktora, 

2.

 

przypisania i inne akcje zdefiniowane w ciele konstruktora 

 
Cechy listy inicjalizacyjnej: 

 

składnik  bez  modyfikatora 

const

  moŜna  inicjalizować  przez  listę  inicjalizacyjną  lub 

przez przypisanie w ciele konstruktora, 

 

składnik typu 

const

 moŜna inicjalizować tylko za pomocą listy inicjalizacyjnej, 

 

lista inicjalizacyjna nie moŜe inicjalizować składnika 

static

 
Przykład 

 : 

#include <iostream> 
#include <string> 
using namespace std; 
//----------------- 
class klasa 

public: 
 

int a; 

 

int b; 

 

const int c; 

 

char tekst[20]; 

 

klasa(int aa, int bb, int cc, char *t); 

 

void wyswietl(); 

}; 
klasa::klasa(int aa, int bb, int cc, char *t) 
 

   

: a(aa), b(bb), c(cc) 


 

strcpy(tekst,t); 

 

wyswietl(); 


void klasa::wyswietl() 

 

cout << "---------------\n"; 

 

cout << tekst << endl; 

 

cout << "a=" << a << " b=" << b << " c=" << c << endl; 

 

cout << "---------------\n"; 


//--------------------- 
int main() 

 

klasa dane(1,2,3,"Dane"); 

return 0; 

background image

Krzysztof Karbowski: Programowanie w języku C++ 

52 

14.6.  Konstrukcja  obiektu,  którego  składnikiem  jest  obiekt  innej 
klasy 

Przykład 

 : 

#include <iostream> 
#include <string> 
using namespace std; 
 
#define MAXDLSTRINGU 50 
 
//--------------------------------- 
class CWyswietlacz 

private: 
 

int m_nMin; 

 

int m_nMax; 

 

int m_nWskazanie; 

 

char m_sOpis[MAXDLSTRINGU]; 

public: 
 

CWyswietlacz(const char* sOpis, int nMin, int nMax, 

 

  int nWskazanie=0); 

 

~CWyswietlacz(); 

 

void Ustaw(int nWartosc); 

 

void Wyswietl(); 

}; 
//------------ 
CWyswietlacz::CWyswietlacz(const char* sOpis, int nMin,  
 

   

 

 

 

   int nMax, int nWskazanie) 

 

   

: m_nMin(nMin), m_nMax(nMax),  

 

   

  m_nWskazanie(nWskazanie) 

{  
 

strcpy(m_sOpis,sOpis); 

 

cout << "Konstruktor wyswietlacza " << m_sOpis << endl; 


//------------ 
CWyswietlacz::~CWyswietlacz() 

 

cout << "Destruktor wyswietlacza " << m_sOpis << endl; 


//------------ 
void CWyswietlacz::Ustaw(int nWartosc) 

 

m_nWskazanie=nWartosc; 


//------------ 
void CWyswietlacz::Wyswietl() 

 

cout << m_sOpis << ": " << m_nWskazanie << endl; 


//--------------------------------- 
class CPrzyrzad 

private: 
 

CWyswietlacz m_objWoltomierz; 

 

CWyswietlacz m_objAmperomierz; 

 

char m_sNazwa[MAXDLSTRINGU]; 

background image

Krzysztof Karbowski: Programowanie w języku C++ 

53 

public: 
 

CPrzyrzad(const char* sNazwa, const char* sWoltOpis, 

 

  int nWoltMin, int nWoltMax, int nWoltWskaz, 

 

  const char* sAmpOpis, int nAmpMin, int AmpMax,  

 

  int nAmpWskaz); 

 

~CPrzyrzad(); 

 

void UstawWolt(int nWartosc); 

 

void UstawAmp(int nWartosc); 

 

void WyswietlWolt(); 

 

void WyswietlAmp(); 

}; 
//----------- 
CPrzyrzad::CPrzyrzad(const char* sNazwa, const char* sWoltOpis, 
 

  int nWoltMin, int nWoltMax, int nWoltWskaz, 

 

  const char* sAmpOpis, int nAmpMin, int nAmpMax,  

 

  int nAmpWskaz) 

 

  : m_objWoltomierz(sWoltOpis,nWoltMin,nWoltMax,  

 

    nWoltWskaz), 

 

    m_objAmperomierz(sAmpOpis,nAmpMin,nAmpMax,nAmpWskaz) 


 

strcpy(m_sNazwa,sNazwa); 

 

cout << "Konstruktor przyrzadu " << m_sNazwa << endl; 


//----------- 
CPrzyrzad::~CPrzyrzad() 

 

cout << "Destruktor przyrzadu " << m_sNazwa << endl; 


//----------- 
void CPrzyrzad::UstawWolt(int nWartosc) 

 

m_objWoltomierz.Ustaw(nWartosc); 


//----------- 
void CPrzyrzad::UstawAmp(int nWartosc) 

 

m_objAmperomierz.Ustaw(nWartosc); 


//----------- 
void CPrzyrzad::WyswietlWolt() 

 

cout << m_sNazwa << "-> "; 

 

m_objWoltomierz.Wyswietl(); 


//----------- 
void CPrzyrzad::WyswietlAmp() 

 

cout << m_sNazwa << "-> "; 

 

m_objAmperomierz.Wyswietl(); 


//----------------------------------------------- 
//----------------------------------------------- 
int main() 

 

CPrzyrzad objMiernik("Miernik", 

 

                   "Woltomierz miernika",0,10,5, 

background image

Krzysztof Karbowski: Programowanie w języku C++ 

54 

 

   

 

 

 

 "Amperomierz miernika",0,10,9); 

 

objMiernik.WyswietlWolt(); 

 

objMiernik.WyswietlAmp(); 

 
 

CPrzyrzad objPanel("Panel", 

 

   

 

 

   "Woltomierz panelu",0,10,1, 

 

   

 

 

   "Amperomierz panelu",0,10,2); 

 

objPanel.UstawWolt(10); 

 

objPanel.UstawAmp(10); 

 

objPanel.WyswietlWolt(); 

 

objPanel.WyswietlAmp(); 

return 0; 

 
Kolejność wywołania konstruktorów: 

1.

 

Konstruktory obiektów składowych, 

2.

 

Konstruktor klasy zawierającej obiekty. 

Kolejność wywoływania destruktorów: 

1.

 

Destruktor klasy zawierającej obiekty. 

2.

 

Destruktory obiektów składowych, 

 

Obiekt  klasy  będącej  składnikiem  innej  klasy  moŜe  być  inicjalizowany 
jedynie za pomocą listy inicjalizacyjnej konstruktora. 

 
Uwagi: 

 

jeśli  klasa  obiektu  składowego  nie  ma  konstruktora,  wtedy  nie  umiescza  się  go  na  liście 
inicjalizacyjnej, 

 

jeśli  klasa  obiektu  składowego  ma  konstruktor  domniemany  (i  ten  konstruktor  chcemy 
uŜyć), to wywołanie tego konstruktora na liście inicjalizacyjnej moŜna pominąć, 

 

jeśli  klasa  obiektu  składowego  ma  konstruktory  inne  niŜ  domniemany,  to  pominięcie 
wywołania konstruktora na liście inicjalizacyjnej spowoduje błąd kompilacji. 

14.7. Konstruktor kopiuj

ą

cy (inicjalizator kopiuj

ą

cy) 

Jest to konstruktor następującego typu: 

klasa::klasa(klasa & obiekt)

Konstruktor  kopiujący  słuŜy  do  skonstruowania  obiektu,  który  jest  kopią  innego,  juŜ 

istniejącego  obiektu  danej  klasy.  Konstruktor  ten  pracuje  gdy  następuje  inicjalizacja  a  nie 
przypisanie obiektu. 

Konstruktor  kopiujący  moŜna  wywołać  z  jednym  argumentem  będącym  referencją 

obiektu  danej  klasy.  Konstruktor  ten  moŜe  mieć  więcej  parametrów,  ale  muszą  to  być 
parametry domniemane. 

 

Przykład jawnego wywołania konstruktora kopiujacego: 

K obiekt_wzor;   

 

 

// definicja obiektu wzorcowego 

K obiekt_nowy = K(obiekt_wzor);  // definicja nowego obiektu 

   albo 

K obiekt_nowy = obiekt_wzor; 

   albo  

K obiekt_nowy(obiekt_wzor)

 
Analogicznie dla typów wbudowanych moŜna by zapisać: 

int wzor = 1; 

background image

Krzysztof Karbowski: Programowanie w języku C++ 

55 

int kopia1 = int(wzor)
int kopia2 = wzor; 
int kopia3(wzor)

 
Niejawne wywołanie konstruktora kopiującego: 

1.

 

podczas przesyłania obiektu do funkcji, gdy przesłanie odbywa się przez wartość, 

2.

 

podczas  zwracania  obiektu  jako  rezultatu  funkcji,  jeśli  funkcja  zwraca  rezultat  przez 
wartość (ta sytuacja moŜe być zaleŜna od implementacji kompilatora – Visual C++ 6.0 
nie utworzy obiektu tymczasowego). 

 

Przykład 

 

#include <iostream> 
#include <string> 
using namespace std; 
//-------------------------- 
class CKlasa 

public: 
 

int m_nLiczba; 

 

char m_sString[30]; 

 

CKlasa(int nLiczba, const char* sString); 

 

CKlasa(const CKlasa &objWzor); 

 

~CKlasa(); 

};  
CKlasa::CKlasa(int nLiczba, const char* sString) 

 

m_nLiczba=nLiczba; 

 

strcpy(m_sString,sString); 

 

cout << "Konstruktor " << m_sString << endl; 


CKlasa::CKlasa(const CKlasa &objWzor) 

 

m_nLiczba=objWzor.m_nLiczba; 

 

strcpy(m_sString,objWzor.m_sString); 

 

cout << "Konstruktor kopiujacy " << m_sString << endl; 


CKlasa::~CKlasa() 

 

cout << "Destruktor " << m_sString << endl; 


//-------------------------- 
void NapiszString(CKlasa objWartosc) 

 

cout << "NapiszString: " << objWartosc.m_sString << endl; 


//-------------------------- 
CKlasa UtworzObiekt(int nLiczba, const char* sString)  

 

CKlasa objLokalny(nLiczba,sString); 

 

return objLokalny; 


//-------------------------- 
int main() 

 

CKlasa objWzorzec(1,"Wzorzec"); 

background image

Krzysztof Karbowski: Programowanie w języku C++ 

56 

 

cout << "--- Obiekt na bazie wzorca---\n"; 

 

CKlasa objKopia=objWzorzec; 

 

// albo 

 

// CKlasa objKopia=CKlasa(objWzorzec); 

 

// albo 

 

//CKlasa objKopia(objWzorzec); 

 

cout << "---Wywolaj <<NapiszString>>---\n"; 

 

NapiszString(objWzorzec); 

 

cout << "---Wywolaj <<UtworzObiekt>>---\n"; 

 

CKlasa objZFunkcji=UtworzObiekt(1,"Z funkcji"); 

 

cout << "----- Koniec programu ---- \n"; 

return 0; 

Jeśli  w  klasie  nie  ma  zdefiniowanego  konstruktora  kopiującego  to  gdy 
zachodzi  potrzeba  wywołania  takiego  konstruktora,  to  kompilator 
wygeneruje 

konstruktor 

kopiujący 

działający 

według 

zasady 

kopiowania "składnik po składniku". 

 
Jeśli  w  programie  wystarczy  kopiowanie  "składnik  po  składniku"  to  nie  ma  potrzeby 
programowania 

konstruktora 

kopiującego 

– 

wystarczy 

konstruktor 

generowany 

automatycznie. 

14.7.1. Sytuacja, gdy niezb

ę

dny jest konstruktor kopiuj

ą

cy 

Przykład 

 

#include <iostream> 
#include <string> 
using namespace std; 
//-------------------------- 
class CKlasa 

public: 
 

char *m_sString; 

 

CKlasa(const char* sString); 

 

CKlasa(const CKlasa &objWzor); 

 

void Zmien(const char* sString); 

 

~CKlasa(); 

}; 
CKlasa::CKlasa(const char* sString) 

 

m_sString = new char[80]; 

 

strcpy(m_sString,sString); 


CKlasa::CKlasa(const CKlasa &objWzor) 

 

m_sString = new char[80]; 

 

strcpy(m_sString,objWzor.m_sString); 


CKlasa::~CKlasa() 

 

delete [] m_sString; 


void CKlasa::Zmien(const char* sString) 

 

strcpy(m_sString,sString); 

background image

Krzysztof Karbowski: Programowanie w języku C++ 

57 


//-------------------------- 
int main() 

 

CKlasa objWzor("obiekt 1"); 

 

CKlasa objKopia=objWzor; 

 

cout << "Wzor:  " << objWzor.m_sString << endl; 

 

cout << "Kopia: " << objKopia.m_sString << endl; 

 

// zmiana tekstu 

 

objKopia.Zmien("obiekt 2"); 

 

cout << "Po zmianie:\n"; 

 

cout << "Wzor:  " << objWzor.m_sString << endl; 

 

cout << "Kopia: " << objKopia.m_sString << endl; 

return 0; 

 
Na ekranie pojawi się następujący tekst: 

Wzor:  obiekt 1 
Kopia: obiekt 1 
Po zmianie: 
Wzor:  obiekt 1 
Kopia: obiekt 2 

Gdyby nie było konstruktora kopiującego pojawiłby się tekst: 

Wzor:  obiekt 1 
Kopia: obiekt 1 
Po zmianie: 
Wzor:  obiekt 2 
Kopia: obiekt 2 

15. Tablice obiektów 

Agregat (skupisko danych) – to tablica obiektów danej klasy lub obiekt danej klasy, który: 

1.

 

nie ma składników 

private

 i 

protected

2.

 

nie ma konstruktorów, 

3.

 

nie ma klas podstawowych, 

4.

 

nie ma funkcji wirtualnych. 

15.1 Tablice obiektów b

ę

d

ą

cych agregatami  

15.1.1 Tworzenie tablic 

Przykład: 

class CKlasa 
{ 
public: 
 

int m_nA; 

 

float m_B; 

}
// ......... 
CKlasa aTablica[5]
for (i=0; i<5; i++) 
{ 
 

aTablica[i].m_nA=1; 

 

aTablica[i].m_B=1.3; 

}

background image

Krzysztof Karbowski: Programowanie w języku C++ 

58 

15.1.2 Inicjalizacja tablic 

Przykład: 

CKlasa aTab[5]= 
 

{ 1, 1.1, 

 

// element aTab[0] 

 

  2, 2.2, 

 

// element aTab[1] 

 

}

 

 

 

// pozostałe elementy zostan

ą

 wypełnione 

 

   

 

 

// zerami 

15.2. Tablice obiektów nie b

ę

d

ą

cych agregatami 

15.2.1. Tworzenie tablic 

Jeśli z obiektów danej klasy naleŜy utworzyć tablicę to: 

 

klasa ta nie moŜe mieć Ŝadnych konstruktorów, 

 

albo klasa ta musi mieć konstruktor domniemany, 

 

albo definiowana tablica musi być zainicjalizowana. 

15.2.2. Inicjalizacja tablic 

Podczas inicjalizacji tablic naleŜy posłuŜyć się konstruktorem. 
Przykład 

: 

#include <iostream> 
#include <string> 
using namespace std; 
//-------------------------- 
class CKlasa 

public: 
 

int m_nLiczba; 

 

char m_sString[30]; 

 

CKlasa(int nLiczba, const char* sString); 

 

~CKlasa(); 

};  
CKlasa::CKlasa(int nLiczba, const char* sString) 

 

m_nLiczba=nLiczba; 

 

strcpy(m_sString,sString); 

 

cout << "Konstruktor " << m_sString << endl; 


CKlasa::~CKlasa() 

 

cout << "Destruktor " << m_sString << endl; 


//-------------------------- 
int main() 

 

 

 

CKlasa aTab[3] = { 

 

  CKlasa(0,"Element0"), 

 

  CKlasa(1,"Element1"), 

 

  CKlasa(2,"Element2") 

 

  };// musza zostac zainicjalizowane WSZYSTKIE elementy 

return 0; 

background image

Krzysztof Karbowski: Programowanie w języku C++ 

59 

15.3. Tablica obiektów definiowana operatorem new 

Przykład: 

class CKlasa 
{ 
public: 
 

int m_nA; 

 

float m_B; 

}
// ......... 
CKlasa *pWsk; 
pWsk = new CKlasa[5]
for (i=0; i<5; i++) 
{ 
 

pWsk[i].m_nA=i; 

 

pWsk[i].m_B=0.1*i; 

} 
delete [] pWsk; 
pWsk = NULL; 

 

 

 
Jeśli  z  obiektów  danej  klasy  naleŜy  utworzyć  tablicę  operatorem 

new

 

to: 

 

tablicy tej nie moŜna zainicjalizować, 

 

klasa ta nie moŜe mieć Ŝadnych konstruktorów, 

 

albo klasa ta musi mieć konstruktor domniemany, 

16. Konwersje 

Konwersja – przekształcenie obiektu danego typu (klasy) na inny typ. 
 
Konwersje obiektu typu A na typ B mogą być zdefiniowane przez: 

1.

 

konstruktor klasy B przyjmujący jako jedyny argument obiekt typu A, 

2.

 

specjalną funkcję konwertującą (operator konwersji) zdefiniowaną w klasie A. 

Po zdefiniowaniu jednej z w/w funkcji konwersje będą zachodziły automatycznie (niejawnie). 

16.1. Konstruktor jako konwerter 

 
Konstruktor  przyjmujący  jeden  argument  określa  konwersję  od  typu 
tego argumentu do typu klasy, do której sam naleŜy. 

 
Przykład 

: 

#include <iostream> 
#include <string> 
using namespace std; 
//-------------------------- 
class CLiczba 

public: 
 

double m_Liczba; 

 

char m_sOpis[30]; 

 

CLiczba(double Liczba, const char* sOpis) 

 

  { m_Liczba=Liczba; strcpy(m_sOpis,sOpis); } 

 

void Napisz(); 

background image

Krzysztof Karbowski: Programowanie w języku C++ 

60 

}; 
void CLiczba::Napisz() 

 

cout << "(" << m_Liczba << ":\"" << m_sOpis << "\")"; 


//-------------------------- 
class CZespol 

public: 
 

double m_Real; 

 

double m_Imag; 

 

CZespol(double Real, double Imag) 

 

  : m_Real(Real), m_Imag(Imag) { } 

 

CZespol(double Real); // konwersja z double 

 

// zamiast powyzszego konwertera mozna zastosowac 

 

// konstruktor: CZespol(double Real, double Imag=0); 

 

CZespol(CLiczba objLiczba); // konwersja z CLiczba 

 

void Napisz(); 

}; 
CZespol::CZespol(double Real) 

 

m_Real=Real; 

 

m_Imag=0; 

 

cout << "<<Konwersja z double>>\n"; 


CZespol::CZespol(CLiczba objLiczba) 

 

m_Real=objLiczba.m_Liczba; 

 

m_Imag=0; 

 

cout << "<<Konwersja z CLiczba>>\n"; 


void CZespol::Napisz() 

 

cout << "(" << m_Real << "+" << m_Imag << "i" << ")"; 


//-------------------------- 
CZespol dodaj(CZespol obj1, CZespol obj2) 

 

CZespol objWynik(0,0); 

 

objWynik.m_Real = obj1.m_Real + obj2.m_Real; 

 

objWynik.m_Imag = obj1.m_Imag + obj2.m_Imag; 

 

return objWynik; 


//--------------------------- 
int main() 

 

CZespol objA(1,1), objB(2,2); 

 

CLiczba objL(3,"trzy"); 

 

double wart=5; 

 

CZespol objWynik(0,0); 

 
 

objWynik=dodaj(objA,objB); 

 

objA.Napisz(); cout << "+"; objB.Napisz(); 

 

cout << "="; objWynik.Napisz(); cout << endl; 

 
 

objWynik=dodaj(objA,wart); 

background image

Krzysztof Karbowski: Programowanie w języku C++ 

61 

 

objA.Napisz(); cout << "+"<< wart; 

 

cout << "="; objWynik.Napisz(); cout << endl; 

 
 

objWynik=dodaj(objA,objL); 

 

objA.Napisz(); cout << "+"; objL.Napisz(); 

 

cout << "="; objWynik.Napisz(); cout << endl; 

return 0; 

16.2. Funkcja konwertuj

ą

ca (operator konwersji) 

Funkcja  konwertująca  (operator  konwersji)  obiektu  klasy  K  na  typ  T  to  funkcja  składowa 
klasy K postaci: 

K::operator T() 

Cechy: 

 

musi być funkcją składową klasy, z której dokonuje konwersji, 

 

nie ma określonego typu zwracanego rezultatu, 

 

ma pustą listę argumentów, 

 

jest dziedziczona, 

 

moŜe być funkcją wirtualną. 

 
Przykład 

: 

#include <iostream> 
#include <string> 
using namespace std; 
//-------------------------- 
class CZespol 

public: 
 

double m_Real; 

 

double m_Imag; 

 

CZespol(double Real=0, double Imag=0) 

 

  : m_Real(Real), m_Imag(Imag) { } 

 

operator double(); 

 

void Napisz(); 

}; 
CZespol::operator double() 

 

cout << "<<Konwersja na double>>\n"; 

 

return m_Real; 


void CZespol::Napisz() 

 

cout << "(" << m_Real << "+" << m_Imag << "i" << ")"; 


//--------------------------- 
int main() 

 

CZespol objA(1,1); 

 

double wynik; 

 

double skladnik; 

 
 

objA.Napisz(); cout << endl; 

 

skladnik=objA; 

 

wynik = 2 + skladnik; 

background image

Krzysztof Karbowski: Programowanie w języku C++ 

62 

 

 

 

cout << "2 + " << skladnik << " = " << wynik << endl; 

return 0; 

16.3. Sytuacje, w których zachodzi konwersja 

Niejawne konwersje zachodzą, gdy: 

1.

 

podczas  wywołania  funkcji  zachodzi  niezgodność  argumentów  aktualnych  z 
argumentami  formalnymi  i  jest  jednoznaczna  moŜliwość  usunięcia  niedopasowania 
poprzez konwersję, 

2.

 

gdy  funkcja  zwraca  rezultat  innego  typu  niŜ  zadeklarowany  i  moŜna  jednoznacznie 
przeprowadzić konwersję, 

3.

 

w obecności operatorów (np.: 

a+b

c-d

), 

4.

 

podczas realizacji wyraŜeń inicjalizujących, 

5.

 

podczas realizacji wyraŜeń:  

if(obj)

..., 

switch(obj)

..., 

while(obj)

...

, for(...; obj ;...)

  

kompilator będzie starał się wykonać konwersję 

(int)obj

 . 

 
Jawne wywołanie konwersji: 

CKlasa obj; 
obj = (CKlasa)obj2; 

// forma rzutowania 

obj = CKlasa(obj2)

// forma wywołania funkcji 

 
 

17. Przeładowanie operatorów 

Funkcja operatorowa: 

typ_zwracany 

operator

 nazwa_operatora ( argumenty ) 

{ 

// ciało funkcji 

}

 

Funkcja operatorowa moŜe być funkcją globalną lub niestatyczną funkcją składową klasy, dla 
której pracuje. 
 
Operatory predefiniowane (kompilator sam wygeneruje funkcję operatorową klasy): 

 

= 

 

przypisanie 

 

&

 (jednoargumentowy) 

pobranie adresu obiektu danej klasy, 

 

new, delete

 

utworzenie i likwidacja obiektu danej klasy 

17.1. Operatory dwuargumentowe 

17.1.1. Operator dwuargumentowy jako funkcja globalna 

Przykład 

 

#include <iostream> 
#include <string> 
using namespace std; 
//-------------------------- 
class CZespol 

public: 

background image

Krzysztof Karbowski: Programowanie w języku C++ 

63 

 

double m_Real; 

 

double m_Imag; 

 

CZespol(double Real=0, double Imag=0) 

 

  : m_Real(Real), m_Imag(Imag) { } 

 

void Napisz(); 

}; 
void CZespol::Napisz() 

 

cout << "(" << m_Real << "+" << m_Imag << "i" << ")"; 


//--------------------------- 
CZespol operator+(CZespol arg1, CZespol arg2) 

 

CZespol wynik; 

 

wynik.m_Real = arg1.m_Real + arg2.m_Real ; 

 

wynik.m_Imag = arg1.m_Imag + arg2.m_Imag ; 

 

return wynik; 


//--------------------------- 
int main() 

 

CZespol objA(1,1); 

 

CZespol objB(2,2); 

 

CZespol objW; 

 
 

objW=objA+objB; 

    // inaczej: 
 

// objW = operator+(objA,objB); 

 

objW.Napisz(); 

 

cout << endl ; 

return 0; 

17.1.2. Operator dwuargumentowy jako funkcja składowa klasy 

Przykład 

: 

#include <iostream> 
#include <string> 
using namespace std; 
//-------------------------- 
class CZespol 

public: 
 

double m_Real; 

 

double m_Imag; 

 

CZespol(double Real=0, double Imag=0) 

 

  : m_Real(Real), m_Imag(Imag) { } 

 

CZespol operator+(CZespol arg2); 

 

void Napisz(); 

}; 
void CZespol::Napisz() 

 

cout << "(" << m_Real << "+" << m_Imag << "i" << ")"; 


//--------------------------- 
CZespol CZespol::operator+(CZespol arg2) 

background image

Krzysztof Karbowski: Programowanie w języku C++ 

64 


 

CZespol wynik; 

 

wynik.m_Real = m_Real + arg2.m_Real ; 

 

// inaczej: 

 

// wynik.m_Real = this->m_Real + arg2.m_Real ; 

 

wynik.m_Imag = m_Imag + arg2.m_Imag ; 

 

return wynik; 


//--------------------------- 
int main() 

 

CZespol objA(1,1); 

 

CZespol objB(2,2); 

 

CZespol objW; 

 
 

objW=objA+objB; 

 

// inaczej: 

 

// objW=objA.operator+(objB); 

 

objW.Napisz(); 

 

cout << endl ; 

return 0; 

 
 

Funkcja operatorowa, która jest funkcją składową klasy – wymaga, aby 
obiekt stojący po lewej stronie znaku operatora był obiektem jej klasy. 
Operator,  który  jest  zwykłą  funkcją  globalną  –  nie  ma  tego 
ograniczenia. 

Funckję operatorową, która pracuje na argumentach klas A i B moŜna zrealizować jako: 

1.

 

funkcję składową klasy A, 

2.

 

funkcję globalną, 

3.

 

funkcję składową klasy B. 

17.2. Operatory jednoargumentowe przedrostkowe (prefiksowe) 

17.2.1. Przedrostkowy operator jednoargumentowy jako funkcja globalna 

Przykład 

: 

#include <iostream> 
#include <string> 
using namespace std; 
//-------------------------- 
class CZespol 

 

friend CZespol operator-(CZespol arg); 

private: 
 

double m_Real; 

 

double m_Imag; 

public: 
 

CZespol(double Real=0, double Imag=0) 

 

  : m_Real(Real), m_Imag(Imag) { } 

 

void Napisz(); 

}; 
void CZespol::Napisz() 

background image

Krzysztof Karbowski: Programowanie w języku C++ 

65 

 

cout << "(" << m_Real << "+" << m_Imag << "i" << ")"; 


//--------------------------- 
CZespol operator-(CZespol arg) 

 

CZespol wynik; 

 

wynik.m_Real = - arg.m_Real ; 

 

wynik.m_Imag = - arg.m_Imag ; 

 

return wynik; 


//--------------------------- 
int main() 

 

CZespol objA(1,1); 

 

CZespol objW; 

 
 

objW= - objA ; 

 

// inaczej: 

 

// objW=operator-(objA); 

 

objW.Napisz(); 

 

cout << endl ; 

return 0; 

17.2.2. Przedrostkowy operator jednoargumentowy jako funkcja 

składowa klasy 

Przykład 

 : 

#include <iostream> 
#include <string> 
using namespace std; 
//-------------------------- 
class CZespol 

public: 
 

double m_Real; 

 

double m_Imag; 

 

CZespol(double Real=0, double Imag=0) 

 

  : m_Real(Real), m_Imag(Imag) { } 

 

CZespol operator-(); 

 

void Napisz(); 

}; 
void CZespol::Napisz() 

 

cout << "(" << m_Real << "+" << m_Imag << "i" << ")"; 


CZespol CZespol::operator-() 

 

CZespol wynik; 

 

wynik.m_Real = - m_Real ; 

 

// inaczej: 

 

// wynik.m_Real = - (this->m_Real) ; 

 

wynik.m_Imag = - m_Imag ; 

 

return wynik; 


//--------------------------- 

background image

Krzysztof Karbowski: Programowanie w języku C++ 

66 

int main() 

 

CZespol objA(1,1); 

 

CZespol objW; 

 
 

objW= - objA ; 

 

// inaczej: 

 

// objW=objA.operator-(); 

 

objW.Napisz(); 

 

cout << endl ; 

return 0; 

17.3. Operatory, które musz

ą

 by

ć

 niestatycznymi funkcjami 

składowymi 

Operatory, które muszą być niestatycznymi funkcjami składowymi: 

= 

[] 

() 

-> 

17.3.1. Operator przypisania = 

Operator przypisania to funkcja postaci: 

klasa & klasa::operator=(klasa & obiekt) 

Przykład 

 : 

#include <iostream> 
#include <string> 
using namespace std; 
//-------------------------- 
class COsoba 

private: 
 

char* m_sImie; 

 

char* m_sNazw; 

public: 

 

 

 

 

 

 

 

 

   

 

 

 

 

 

 

// konstruktor 

 

COsoba(const char* sImie, const char* sNazw); 

 

 

COsoba(const COsoba& objWzor); 

// konstr.kopiujacy 

 

~ COsoba();   

 

 

 

 

// destruktor 

 

   

 

 

 

// operator przypisania 

 

COsoba& operator=(const COsoba& objWzor); 

 

void Napisz(); 

}; 
//=========== 
COsoba::COsoba(const char* sImie,const char* sNazw) 
// konstruktor 

 

m_sImie = new char[strlen(sImie)+1]; 

 

strcpy(m_sImie,sImie); 

 

m_sNazw = new char[strlen(sNazw)+1]; 

 

strcpy(m_sNazw,sNazw);   

 

cout << "Konstruktor "; Napisz(); 


//============ 
COsoba::COsoba(const COsoba& objWzor) 
// konstr.kopiujacy 

background image

Krzysztof Karbowski: Programowanie w języku C++ 

67 

 

m_sImie = new char[strlen(objWzor.m_sImie)+1]; 

 

strcpy(m_sImie,objWzor.m_sImie); 

 

m_sNazw = new char[strlen(objWzor.m_sNazw)+1]; 

 

strcpy(m_sNazw,objWzor.m_sNazw); 

 

cout << "Konstruktor kopiujacy "; Napisz(); 


//============ 
COsoba::~COsoba() 
//destruktor 

 

cout << "destruktor "; Napisz(); 

 

delete [] m_sImie; 

 

delete [] m_sNazw; 


//============= 
COsoba& COsoba::operator=(const COsoba& objWzor) 
//operator przypisania 

 

// destruktor 

 

delete m_sImie; 

 

delete m_sNazw; 

 

// konstruktor kopiujacy 

 

m_sImie = new char[strlen(objWzor.m_sImie)+1]; 

 

strcpy(m_sImie,objWzor.m_sImie); 

 

m_sNazw = new char[strlen(objWzor.m_sNazw)+1]; 

 

strcpy(m_sNazw,objWzor.m_sNazw); 

 

cout << "Operator przypisania "; Napisz(); 

 

return *this; 


//============= 
void COsoba::Napisz() 

 

cout << m_sImie << " " << m_sNazw << endl; 


//------------------------------------- 
int main() 

 

COsoba objJan("Jan","Kowalski"); 

 

COsoba objJan2=objJan; 

 

COsoba objPusty("pusty","pusty"); 

 
 

objPusty=objJan; 

 

//inaczej: objPusty.operator=(objJan); 

 
 

objJan.Napisz(); 

 

objJan2.Napisz(); 

 

objPusty.Napisz(); 

return 0; 

 
Sytuacje, w których operator przypisania nie jest generowany automatycznie: 

1.

 

jeŜeli klasa ma składnik const – składnik taki moŜna tylko inicjalizować, 

2.

 

jeŜeli klasa ma składnik będący referencją – referencję moŜna tylko inicjalizować. 

background image

Krzysztof Karbowski: Programowanie w języku C++ 

68 

17.4. Operator wysyłania/pobierania danych do/z strumienia (<<, >>) 

Przykład 

: 

#include <iostream> 
using namespace std; 
//-------------------------- 
class CZespol 

 

friend ostream& operator<<(ostream& ekran,  

 

   

 

 

 

 

   CZespol& objL); 

 

friend istream& operator>>(istream& klawiatura, 

 

   

 

 

 

 

    CZespol& objL); 

private: 
 

double m_Real; 

 

double m_Imag; 

public: 
 

CZespol(double Real=0, double Imag=0) 

 

  : m_Real(Real), m_Imag(Imag) { } 

}; 
//----------------------------- 
ostream& operator<<(ostream& ekran, CZespol& objL) 

 

ekran << "(" << objL.m_Real << "+"  

 

  << objL.m_Imag << "i" << ")"; 

 

return ekran; 


//------------------------------- 
istream& operator>>(istream& klawiatura, CZespol& objL) 

 

cout << "\tCzesc rzeczywista: "; 

 

klawiatura >> objL.m_Real; 

 

cout << "\tCzesc urojona: "; 

 

klawiatura >> objL.m_Imag; 

 

return klawiatura; 


//--------------------------- 
int main() 

 

CZespol objA; 

 
 

cout << "Podaj liczbe zespolona:\n"; 

 

cin >> objA; 

 

cout << "Liczba zespolona: " << objA << endl ; 

 

// poniewaz operator << jest lewostronnie ł

ą

czny 

 

// mozna inaczej zapisac: 

 

// ( ( (cout << "Liczba zespolona: ") << objA ) << endl ); 

 

// lub inaczej: 

 

// (operator<<((cout << "Liczba zespolona: "),objA)) << 

endl; 
return 0; 

18. Dziedziczenie 

Dziedziczenie polega na definiowaniu klasy, która jest odmianą innej klasy: 

class CKlasaPodstawowa 

background image

Krzysztof Karbowski: Programowanie w języku C++ 

69 

{ 
 

//.............. 

}
class CKlasaPochodna : CKlasaPodstawowa 
{ 
 

//............... 

}

 
Przykład 

: 

#include <iostream> 
#include <string> 
using namespace std; 
//------------------------------------------------------------ 
class COsoba 

public: 
 

char m_sImie[80]; 

 

char m_sNazwisko[80]; 

 

int m_nWaga; 

 

int m_nWzrost; 

 

COsoba(char* sImie, char* sNazwisko, int nWaga,  

 

     int nWzrost); 

 

~COsoba(); 

 

void WypiszDane(); 

}; 
//----------------------------------------------------------- 
COsoba::COsoba(char* sImie, char* sNazwisko, int nWaga,  
 

   

   int nWzrost) 

 

: m_nWaga(nWaga), m_nWzrost(nWzrost) 


 

strcpy(m_sImie,sImie); 

 

strcpy(m_sNazwisko,sNazwisko); 

 

cout << "Konstruktor obiektu :" << m_sNazwisko  

 

   << " klasy COsoba\n"; 


//----------------------------------------------------------- 
COsoba::~COsoba() 

 

cout << "Destruktor obiektu :" << m_sNazwisko  

 

   << " klasy COsoba\n"; 


//----------------------------------------------------------- 
void COsoba::WypiszDane() 

 

cout << m_sImie << " " << m_sNazwisko << "; " << m_nWaga << 

 

      " kg; " << m_nWzrost << " cm\n"; 


//------------------------------------------------------------ 
//------------------------------------------------------------ 
class COsobaZAdresem : public COsoba 

public: 
 

char m_sUlica[80]; 

 

char m_sMiasto[80]; 

 

COsobaZAdresem(char* sImie, char* sNazwisko, int nWaga,  

Lista pochodzenia 

background image

Krzysztof Karbowski: Programowanie w języku C++ 

70 

 

   

 

   int nWzrost, char* sUlica, char* sMiasto); 

 

~COsobaZAdresem(); 

 

void WypiszDane(); 

}; 
//------------------------------------------------------------ 
COsobaZAdresem::COsobaZAdresem(char* sImie, char* sNazwisko,  
 

   

 

 

 

 

   int nWaga, int nWzrost,  

 

   

 

 

 

 

   char* sUlica, char* sMiasto) 

 

   

 

: COsoba(sImie,sNazwisko,nWaga,nWzrost) 


 

strcpy(m_sUlica,sUlica); 

 

strcpy(m_sMiasto,sMiasto); 

 

cout << "Konstruktor obiektu :" << m_sNazwisko  

 

   << " klasy COsobaZAdresem\n"; 


//------------------------------------------------------------ 
COsobaZAdresem::~COsobaZAdresem() 

 

cout << "Destruktor obiektu :" << m_sNazwisko  

 

   << " klasy COsobaZAdresem\n"; 


//------------------------------------------------------------ 
void COsobaZAdresem::WypiszDane() 

 

cout << m_sImie << " " << m_sNazwisko << "; " << m_nWaga << 

 

      " kg; " << m_nWzrost << " cm; ul." << m_sUlica << 

 

   

"; " << m_sMiasto << endl; 


//------------------------------------------------------------- 
//------------------------------------------------------------- 
 
int main() 

 

COsoba  objKowalski("Jan","Kowalski",65,178); 

 

objKowalski.WypiszDane(); 

 
 

COsobaZAdresem 

objNowak("Adam","Nowak",81,180,"Dluga","Krakow"); 
 

objNowak.WypiszDane(); 

return 0; 

 
Dziedziczenie powoduje zagnieŜdŜenie zakresów obiektów: 
 

class CKlasaPodstawowa 
{ 
public: 
 

int x; 

 

int y; 

}
class CKlasaPochodna : public CKlasaPodstawowa 
{ 
public: 
 

int x; 

 

int y; 

background image

Krzysztof Karbowski: Programowanie w języku C++ 

71 

}
 

W powyŜszym przykładzie składniki 

x

 i 

y

 klasy 

CKlasaPochodna

 zasłonią składniki 

x

 i 

y

 

klasy 

CKlasaPodstawowa

 
Zakresy waŜności w klasie 

COsobaZAdresem

COsobaZAdresem 
{ 

char m_sImie[80]

 

char m_sNazwisko[80]

 

int m_nWaga; 

 

int m_nWzrost; 
void WypiszDane()
{ 
 

char m_sUlica[80]

 

char m_sMiasto[80]

 

void WypiszDane()

} 

} 

Funkcja 

WypiszDane

  w  klasie 

COsobaZAdresem

  zasłoni  funkcję 

WypiszDane

  z  klasy 

COsoba

. Funkcje te nie są funkcjami przeładowanymi, gdyŜ mają róŜne zakresy waŜności. 

 
W klasie pochodej moŜna zdefiniować: 

 

dodatkowe dane składowe, 

 

dodatkowe funkcje składowe, 

 

składniki, które juŜ istnieją w klasie podstawowej. 

 

W  zdefiniowanym  obiekcie  klasy  pochodnej  będzie  zawarty  fragment 
będący jakby obiektem klasy podstawowej, ale dziedziczenie nie polega 
na tworzeniu obiektów pochodnych tylko klas pochodnych. 

 
Dostęp do zasłoniętych składników: 

COsobaZAdresem Kowalski; 
 
 

//wywołanie funkcji z klasy pochodnej COsobaZAdresem 

Kowalski.WypiszDane()
 
 

//wywołanie funkcji z klasy podstawowej COsoba 

Kowalski.COsoba::WypiszDane()

18.1. Dost

ę

p do składników klasy podstawowej 

18.1.1. Prywatne składniki klasy podstawowej 

 
Prywatne składniki klasy podstawowej są dziedziczone, ale w zakresie klasy pochodnej oraz 

z poza klasy nie ma do nich dostępu. 

18.1.2. Nieprywatne składniki klasy podstawowej 

 
Składniki 

public

 – są dziedziczone i dostępne w zakresie klasy pochodnej oraz z poza klasy. 

 

Odziedziczone 

po COsoba 

background image

Krzysztof Karbowski: Programowanie w języku C++ 

72 

Składniki 

protected

  –  są  dziedziczone  i  dostępne  w  zakresie  klasy  pochodnej  ale  nie  są 

dostępne z poza klasy. 

18.1.3.  Dost

ę

p  do  składników  klasy  podstawowej  okre

ś

lony  przez  klas

ę

 

pochodn

ą

 

 
Rodzaje dziedziczenia: 

class CklasaPodstawowa : public CKlasaPochodna 
class CklasaPodstawowa : protected CKlasaPochodna 
class CklasaPodstawowa : private CKlasaPochodna 

 
Jeśli  na  liście  dziedziczenia  nie  określi  się  jego  typu  to  przyjęte  zostanie  dziedziczenie  typu 

private

 
Dziedziczenie typu 

public

 

 

klasa 

podstawowa 

 

klasa 

pochodna 

 

sk

ła

d

n

ik

private 

 

private 

sk

ła

d

n

ik

protected 

 

protected 

public 

 

public 

 
Dziedziczenie typu 

protected

 

 

klasa 

podstawowa 

 

klasa 

pochodna 

 

sk

ła

d

n

ik

private 

 

private 

sk

ła

d

n

ik

protected 

 

protected 

public 

 

protected 

 
Dziedziczenie typu 

private

 

 

klasa 

podstawowa 

 

klasa 

pochodna 

 

sk

ła

d

n

ik

private 

 

private 

sk

ła

d

n

ik

protected 

 

private 

public 

 

private 

18.2. Wyj

ą

tki w dziedziczeniu 

 
Nie dziedziczy się: 

 

konstruktorów 

 

operatora przypisania 

 

destruktora 

 

background image

Krzysztof Karbowski: Programowanie w języku C++ 

73 

18.3. Kolejno

ść

 wywoływania konstruktorów 

Przykład 

 

#include <iostream> 
using namespace std; 
 
class CZarowka 

protected: 
 

int m_nMoc; 

public: 
 

CZarowka(int nMoc); 

 

~CZarowka(); 

 

void Zaswiec(); 

}; 
//----------------------------------------------- 
CZarowka::CZarowka(int nMoc)  
 

   

 

 

: m_nMoc(nMoc) 


 

cout << "Konstruktor CZarowka; moc=" 

 

   << m_nMoc << endl; 


//----------------------------------------------- 
CZarowka::~CZarowka() 

 

cout << "Destruktor CZarowka; moc=" 

 

   << m_nMoc << endl; 


//----------------------------------------------- 
void CZarowka::Zaswiec() 

 

cout << "Swieci zarowka o mocy "  

 

   << m_nMoc << endl; 


//----------------------------------------------- 
//----------------------------------------------- 
class CStarter 

public: 
 

int m_nTyp; 

 

CStarter(int nTyp); 

 

~CStarter(); 

}; 
//----------------------------------------------- 
CStarter::CStarter(int nTyp) 
 

   

: m_nTyp(nTyp) 


 

cout << "Konstruktor CStarter; Typ "  

 

   << m_nTyp << endl; 


//----------------------------------------------- 
CStarter::~CStarter() 

 

cout << "Destruktor CStarter; Typ "  

 

   << m_nTyp << endl; 

background image

Krzysztof Karbowski: Programowanie w języku C++ 

74 

//----------------------------------------------- 
//----------------------------------------------- 
class CSwietlowka : public CZarowka 

protected: 
 

int m_nMocEkw; //ekwiwalent mocy 

 

CStarter m_objStarter; 

public: 
 

CSwietlowka(int nMoc, int nMocEkw,  

 

   

 

int nTypStartera); 

 

~CSwietlowka(); 

 

void Zaswiec(); 

}; 
//----------------------------------------------- 
CSwietlowka::CSwietlowka(int nMoc, int nMocEkw,  
 

   

 

 

 

 int nTypStartera) 

 

: CZarowka(nMoc),m_objStarter(nTypStartera),  

 

  m_nMocEkw(nMocEkw) 


 

cout << "Konstruktor CSwietlowka; moc="  

 

   << m_nMoc << endl; 


//----------------------------------------------- 
CSwietlowka::~CSwietlowka() 

 

cout << "Destruktor CSwietlowka; moc="  

 

   << m_nMoc << endl; 


//----------------------------------------------- 
void CSwietlowka::Zaswiec() 

 

cout << "Swieci swietlowka o mocy "  

 

   << m_nMoc << endl; 


//----------------------------------------------- 
//----------------------------------------------- 
//----------------------------------------------- 
int main() 

 

CSwietlowka objLampa(100,15,1); 

 

objLampa.Zaswiec(); 

return 0; 

 
Kolejność wywoływania konstruktorów: 

1.

 

konstruktory klas podstawowych (starszych w hierarchii), 

2.

 

konstruktory obiektów będących składnikami klasy pochodnej, 

3.

 

konstruktor obiektu klasy pochodnej. 

 

18.4. Przypisanie i inicjalizacja obiektów w warunkach dziedziczenia 

 
Klasa  pochodna  nie  dziedziczy  operatora  przypisania  oraz  konstruktorów  (w  szczególności 
konstruktora kopiującego). 

background image

Krzysztof Karbowski: Programowanie w języku C++ 

75 

 
Gdy  klasa  pochodna  nie  definiuje  swojego  operatora  przypisania  to  kompilator  wygeneruje 

operator  przypisania  pracujący  metodą  „składnik  po  składniku”.  Oznacza  to,  Ŝe  dla 
typów wbudowanych zrobi ich kopie a dla typów zdefiniowanych przez uŜytkownika 
(klas)  wykorzysta  operatory  przypisania  tych  klas  (o  ile  istnieją).  TakŜe  dla  klasy 
podstawowej wykorzysta jej operator przypisania (jeśli go posiada) w części będącej 
dziedzictwem. 

 
Gdy  klasa  pochodna  nie  definiuje  swojego  konstruktora  kopiującego  to  kompilator 

wygeneruje taki konstruktor pracujący metodą „składnik po składniki) (analogicznie 
jak dla operatora przypisania). 

 

18.4.1. Definiowanie konstruktora kopiuj

ą

cego i operatora przypisania 

Przykład 

 

#include <iostream> 
using namespace std; 
//----------------------------------------------- 
class CPrzodek 

public: 
 

int m_A; 

 

CPrzodek(int A); 

 

CPrzodek(const CPrzodek& Wzor); 

 

~CPrzodek(); 

 

CPrzodek& operator=(const CPrzodek& Wzor); 

}; 
//----------------------------------------------- 
CPrzodek::CPrzodek(int A) 
 

   

: m_A(A) 


 

cout << "Konstruktor CPrzodek: " 

 

   << m_A << endl; 


//----------------------------------------------- 
CPrzodek::CPrzodek(const CPrzodek& Wzor) 

 

m_A=Wzor.m_A; 

 

cout << "Konstruktor kopiujacy CPrzodek: " 

 

   << m_A << endl; 


//----------------------------------------------- 
CPrzodek::~CPrzodek() 

 

cout << "Destruktor CPrzodek: " << m_A << endl; 


//----------------------------------------------- 
CPrzodek& CPrzodek::operator=(const CPrzodek& Wzor) 

 

m_A=Wzor.m_A; 

 

cout << "Operator przypisania CPrzodek: " 

 

   << m_A << endl; 

 

return *this; 

background image

Krzysztof Karbowski: Programowanie w języku C++ 

76 

//----------------------------------------------- 
//----------------------------------------------- 
class CPotomek : public CPrzodek 

public: 
 

int m_B; 

 

CPotomek(int A, int B); 

 

CPotomek(const CPotomek& Wzor); 

 

~CPotomek(); 

 

CPotomek& operator=(const CPotomek& Wzor); 

}; 
//----------------------------------------------- 
CPotomek::CPotomek(int A, int B) 
 

: CPrzodek(A), m_B(B) 


 

cout << "Konstruktor CPotomek: " 

 

   << m_B << endl; 


//----------------------------------------------- 
CPotomek::CPotomek(const CPotomek& Wzor) 
 

   

 

: CPrzodek(Wzor) 


 

m_B=Wzor.m_B; 

 

cout << "Konstruktor kopiujacy CPotomek: " 

 

   << m_B << endl; 


//----------------------------------------------- 
CPotomek::~CPotomek() 

 

cout << "Destruktor CPotomek: " 

 

   << m_B << endl; 


//----------------------------------------------- 
CPotomek& CPotomek::operator=(const CPotomek& Wzor) 

 

// wywolanie operatora przypisania klasy  

 

// podstawowej; 

 

// jako parametr aktualny operatora mozna podac 

 

// "Wzor" gdyz referencja do obiektu klasy 

 

// pochodnej moze wystapic zamiast referencji  

 

// do obiektu klasy podstawowej 

 

(*this).CPrzodek::operator=(Wzor); 

 
 

m_B=Wzor.m_B; 

 

cout << "Operator przypisania CPotomek: " 

 

   << m_B << endl; 

 

return *this; 


//----------------------------------------------- 
//----------------------------------------------- 
//----------------------------------------------- 
int main() 

 

CPotomek obj1(1,1); 

 

CPotomek obj2=obj1; 

 

CPotomek obj3(3,3); 

background image

Krzysztof Karbowski: Programowanie w języku C++ 

77 

 
 

obj3=obj1; 

return 0; 

18.5. Konwersje standardowe przy dziedziczeniu 

 
Wskaźnik do obiektu klasy pochodnej moŜe być niejawnie przekształcony na wskaźnik 

dostępnej jednoznacznie klasy podstawowej. 

 
Referencja  obiektu  klasy  pochodnej  moŜe  być  niejawnie  przekształcona  na  referencję 

jednoznacznie dostępnej klasy podstawowej. 

 
Przykład 

  

#include <iostream> 
using namespace std; 
//----------------------------------------------- 
class CSamochod 

public: 
 

int m_Paliwo; 

}; 
//----------------------------------------------- 
class CFiat : public CSamochod 

public: 
 

int m_LiczbaMiejsc; 

}; 
//----------------------------------------------- 
class CCosDoJezdzenia : private CSamochod 

public: 
 

int m_LiczbaMiejsc; 

}; 
//----------------------------------------------- 
//----------------------------------------------- 
void Zatankuj(CSamochod& Klient) 

 

Klient.m_Paliwo =100; 


//----------------------------------------------- 
//----------------------------------------------- 
int main() 

 

CFiat objFIAT; 

 

CCosDoJezdzenia objSAM; 

 
 

// niejawna konwersja refernecji CFiat   

 

// na CSamochod 

 

Zatankuj(objFIAT); 

 
 

// Zatankuj(objSAM); BLAD gdyz CCosDoJezdzenia 

 

//                   dziedziczy CSamochod jako 

 

//                   private 

background image

Krzysztof Karbowski: Programowanie w języku C++ 

78 

 
 

// jawna konwersja refernecji CCosDoJezdzenia   

 

// na CSamochod 

 

Zatankuj((CSamochod&)objSAM); 

return 0; 

 

 
Sytuacje, w których zachodzą konwersje standardowe: 

 

podczas przysłania argumentów do funkcji (jako referencji lub wskaźnika). 
Funkcję przyjmującą argument będący referencją obiektu klasy podstawowej moŜna 
wywołać z argumentem będącym referencją obiektu klasy pochodnej. Analogicznie 
jest ze wskaźnikami. 

 

przy zwracaniu przez funkcję rezultatu będącego referencją lub wskaźnikiem. 
Funkcja zdefiniowana jako zwracająca referencję (lub wskaźnik) obiektu klasy 
podstawowej moŜe zwracać referencję (lub wskaźnik) obiektu klasy pochodnej. 

 

przy przeładowanych operatorach. 
Jeśli funkcja operatorowa spodziewa się obiektu (lub jego referencji) klasy 
podstawowej, to moŜna ją wywołać z obiektem (lub referencją)klasy pochodnej. 

 

w wyraŜeniach inicjalizujących. 
Gdy ma nastąpić inicjalizacja obiektu klasy podstawowej to jako obiekt wzorcowy 
moŜna wykorzystać obiekt klasy potomnej (gdyŜ konstruktor kopiujący przyjmuje 
referencję obiektu). 

 

Konwersje  standardowe  zachodzą  tylko  podczas  pracy  z  referencjami 
lub wskaźnikami obiektów, a nie z samymi obiektami. 
 
Obiekty klas pochodnych mogą być traktowane jako obiekty swych klas 
podstawowych  tylko  podczas  pracy  na  ich  wskaźnikach  lub 
referencjach. 

19. Funkcje wirtualne 

Definiowanie funkcji wirtualnej: 

class nazwa_klasy 
{ 
 

// ciało klasy 

 

virtual typ nazwa_funkcji(/* parametry */) 

 

{ 

 

  // ciało funkcji 

 

} 

}

albo 

class nazwa_klasy 
{ 
 

// ciało klasy 

 

virtual typ nazwa_funkcji(/* parametry */)

}
typ nazwa_klasy::nazwa_funkcji(/* parametry */) 
{ 
 

// ciało funkcji 

} 

 

background image

Krzysztof Karbowski: Programowanie w języku C++ 

79 

Przykład 

  

#include <iostream> 
using namespace std; 
//----------------------------------------------- 
class CInstrument 

public: 
 

virtual void Zagraj() 

 

{ cout << "Dzwiek\n"; } 

}; 
//----------------------------------------------- 
class CSkrzypce : public CInstrument 

public: 
 

virtual void Zagraj() 

 

{ cout << "Dzwiek skrzypiec\n"; } 

}; 
//----------------------------------------------- 
class CFortepian : public CInstrument 

public: 
 

virtual void Zagraj() 

 

{ cout << "Dzwiek fortepianu\n"; } 

}; 
//----------------------------------------------- 
void Muzyk(CInstrument& objInstr) 

 

objInstr.Zagraj(); 


//----------------------------------------------- 
//----------------------------------------------- 
int main() 

 

CInstrument objInstrument; 

 

CSkrzypce objSkrzypce; 

 

CFortepian objFortepian; 

 

CInstrument* pInstrument; 

 
 

cout << "Wywolanie poprzez obiekt\n"; 

 

objInstrument.Zagraj(); 

 

objSkrzypce.Zagraj(); 

 

objFortepian.Zagraj(); 

 
 

cout << "\nWywolanie poprzez wskaznik\n"; 

 

pInstrument = &objInstrument; 

 

pInstrument->Zagraj(); 

 

pInstrument = &objSkrzypce; 

 

pInstrument->Zagraj(); 

 

pInstrument = &objFortepian; 

 

pInstrument->Zagraj(); 

 
 

cout << "\nWywolanie poprzez referencje\n"; 

 

Muzyk(objInstrument); 

 

Muzyk(objSkrzypce); 

 

Muzyk(objFortepian); 

return 0; 

background image

Krzysztof Karbowski: Programowanie w języku C++ 

80 

 
Rodzaje powiązań wywołań funkcji z adresami określającymi, gdzie są te funkcje: 

wczesne wiązanie – wiązanie na etapie kompilacji, 
późne wiązanie – wiązanie na etapie wykonania programu. 

 
Cechy funkcji wirtualnych: 

 

róŜny zakres waŜności, 

 

te same nazwy, 

 

te same parametry, 

 

ten sam typ. 

Sytuacje, w których dla funkcji wirtualnych zachodzi wczesne wiązanie: 

 

wywołanie na rzecz obiektu: 

obiekt.funkcja();

 

 

jawne uŜycie kwalifikatora zakresu: 

wska

ź

nik->klasa::funkcja();

 

 

wywołanie z konstruktora/destruktora klasy podstawowej. 

 
Klasa abstrakcyjna – klasa, która nie reprezentuje Ŝadnego obiektu. 
 
Funkcja czysto wirtualna – funkcja zadeklarowana w klasie abstrakcyjnej jako: 

 

   virtual typ nazwa(/* parametry *)=0; 

 
Jeśli  klasa  deklaruje  jedną  ze  swoich  funkcji  jako 

virtual

  wówczas  jej  destruktor 

powinien  zostać  zadeklarowany  jako 

virtual

  –  (jest  to  wyjątek  od  reguły,  Ŝe  funkcje 

wirtualne muszą mieć tę samą nazwę). 
 
Przykład 

 A

 

Plik „Pracownik.h” 

#ifndef _PRACOWNIK_H_ 
#define _PRACOWNIK_H_ 
//----------------------------------------- 
class CPracownik 

public: 
 

char m_sImie[80]; 

 

char m_sNazwisko[80]; 

 

CPracownik(char* sImie, char* sNazwisko); 

 

virtual void Napisz()=0; 

}; 
//----------------------------------------- 
void Wizytowka(CPracownik* Dane); 
//----------------------------------------- 
#endif // _PRACOWNIK_H_ 

background image

Krzysztof Karbowski: Programowanie w języku C++ 

81 

 
Plik “Pracownik.cpp” 

 
#include <iostream> 
#include <string> 

using namespace std; 

#include "Pracownik.h" 
//----------------------------------------- 
CPracownik::CPracownik(char* sImie, char* sNazwisko) 

 

strcpy(m_sImie,sImie); 

 

strcpy(m_sNazwisko,sNazwisko); 


//------------------------------------------ 
 
void Wizytowka(CPracownik* Dane) 

 

cout << "******************************\n"; 

 

cout << "Politechnika Krakowska\n"; 

 

cout << "Katedra Inzynierii Procesow Produkcyjnych\n"; 

 

Dane->Napisz(); 

 

cout << Dane->m_sImie << " " << Dane->m_sNazwisko << endl; 

 

cout << "******************************\n"; 

 
Plik „main.cpp” 

#include <iostream> 
using namespace std; 
#include "Pracownik.h" 
//------------------------------------------- 
class CAsystent : public CPracownik 

public: 
 

CAsystent(char* sImie, char* sNazwisko) 

 

  : CPracownik(sImie,sNazwisko) {} 

 

virtual void Napisz(); 

}; 
//--------- 
void CAsystent::Napisz() 

 

cout << "Mgr inz.\n"; 


//------------------------------------------- 
class CAdiunkt : public CPracownik 

public: 
 

CAdiunkt(char* sImie, char* sNazwisko) 

 

  : CPracownik(sImie,sNazwisko) {} 

 

virtual void Napisz(); 

}; 
//--------- 
void CAdiunkt::Napisz() 

 

cout << "Dr inz.\n"; 


//------------------------------------------- 
class CProfesor : public CPracownik 

background image

Krzysztof Karbowski: Programowanie w języku C++ 

82 


public: 
 

CProfesor(char* sImie, char* sNazwisko) 

 

  : CPracownik(sImie,sNazwisko) {} 

 

virtual void Napisz(); 

}; 
//--------- 
void CProfesor::Napisz() 

 

cout << "Prof. dr hab. inz.\n"; 


//------------------------------------------- 
int main() 

 

CAsystent Asystent("Jan","Nowak"); 

 

CAdiunkt Adiunkt("Adam","Kowalski"); 

 

CProfesor Profesor("Jozef","Adamski"); 

 
 

cout << endl; 

 

Wizytowka(&Asystent); 

 
 

cout << endl; 

 

Wizytowka(&Adiunkt); 

 
 

cout << endl; 

 

Wizytowka(&Profesor); 

return 0;