Programowanie w języku C++
Krzysztof Karbowski
Politechnika Krakowska
Kraków 2003
Krzysztof Karbowski: Programowanie w języku C++ 2
Wydanie: 24.10.2009
Krzysztof Karbowski: Programowanie w języku C++ 3
Åšrodowisko Visual Studio 2005.
File New Project... :
Rys.1.
Rys.2
Krzysztof Karbowski: Programowanie w języku C++ 4
Project Add New Item &
Rys.3.
Kompilacja programu: Build Build Solution (F7).
Uruchomienie programu: "Debug Debug Without Debugging" (Ctrl+F5)
Krzysztof Karbowski: Programowanie w j 5
Programowanie w języku C++
Kompilator Dev-C++
C++
www.bloodshed.net
File New Project...
Krzysztof Karbowski: Programowanie w j 6
Programowanie w języku C++
Krzysztof Karbowski: Programowanie w języku C++ 7
1. Pierwszy program.
wariant 1:
#include
using namespace std;
int main()
{
cout << "Pierwszy program \n" ;
return 0;
}
wariant 2:
#include
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
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
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
Krzysztof Karbowski: Programowanie w języku C++ 8
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 (i < 5)
{
cout << "liczba mniejsza od 5" ;
cout << endl ;
i = 5 ;
} // tu NIE MA srednika
else
{
cout << "Liczba nie jest mniejsza od 5" ;
cout << endl ;
}
Krzysztof Karbowski: Programowanie w języku C++ 9
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
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
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:
Krzysztof Karbowski: Programowanie w języku C++ 10
for (i = 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
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
using namespace std;
// rozpoznawanie cyfr
int main()
{
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
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 (i < 4) {
i = i + 1 ;
}
Przykład 2 (Visual Studio 6.0):
while (i < 4)
{
i = i + 1 ;
}
Przykład 3:
while (i < 4)
{
i = 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:
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
using namespace std;
int main()
{
int a ;
a=1;
int b; // deklaracja/definicja obiektu
Krzysztof Karbowski: Programowanie w języku C++ 14
b=a+1
cout << b;
return 0;
}
4.5. Stałe dosłowne
4.5.1. Stałe będące liczbami całkowitymi:
np.: 17 -33 0 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-3
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
* wskaznik 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 *p ; // wskaznik do obiektu typu float
char func() ; //funkcja zwracajÄ…ca obiekt typu char
Krzysztof Karbowski: Programowanie w języku C++ 15
5.6.1. Typ void
void *p ; - oznacza, \e p jest wskaznikiem 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
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=" <<
::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ózniejszym 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
{
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:
a = b + c ;
a = b c ;
a = b * c ;
a = b / c ;
a = (c + d + 3.1) / f ;
5.1.1. Operator modulo
Oblicza resztÄ™ z dzielenia
a = b % c ;
5.1.2. Jednoargumentowe operatory + i
Przykład:
+12.7 -x -(a*b)
5.1.3. Operatory inkrementacji i dekrementacji
i = i + 1 ; mo\na zastąpić i++ ;
k = 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 << ++a << 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 =
m = 27.9
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
using namespace std;
int main()
{
int a=10;
int b=5;
cout << "a=" << a << " b=" << b << endl;
if (a=b) // tu powinno byc a==b
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" ;
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 = i + 2 i += 2
i = i 2 i -= 2
i = i * 2 i *= 2
i = i / 2 i /= 2
i = i % 2 i %= 2
i = i >> 2 i >>= 2
i = i << 2 i <<= 2
i = i & 2 i &= 2
i = i | 2 i |= 2
i = 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;
c = (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
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
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
int main()
{
char znak;
for (znak= a ; znak<= z ; znak++)
cout << znak ;
cout << endl ;
return 0;
}
Przykład :
Temat: Obliczanie n! .
#include
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;
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
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
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;
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
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 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
using namespace std;
long potega(long liczba, int stopien);
void koniec();
//------------------------
int main()
{
long pocz, kon, i;
cout << "Podaj poczatek przedzialu: ";
cin >> pocz;
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 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 wskaznik.
Przykład :
Temat: przesyłanie argumentów przez wartość i przez referencję.
#include
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";
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 yLE
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.
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.
Krzysztof Karbowski: Programowanie w j 25
Programowanie w języku C++
6.7. Obiekty w programie składaj z kilku plików
6.7. Obiekty w programie składającym się z kilku plików
Przykład :
Plik main.cpp:
#include iostream>
using namespace std;
std;
#include "funkcja1.h"
#include "funkcja1.h"
#include "funkcja2.h"
#include "funkcja2.h"
int a; //definicja zmiennej globalnej
//definicja zmien
int main()
{
int x, y;
cout << "Podaj zmienna globalna a=";
cout << "Podaj zmienna globalna a=";
cin >> a;
cout << "Podaj x=";
cout << "Podaj x=";
cin >> x;
cout << "Podaj y=";
cout << "Podaj y=";
cin >> y;
Wypisz_a();
cout << "x+y=" << dodaj(x,y) << endl;
cout << "x+y=" << dodaj(x,y) << endl;
cout << "x-y=" << odejmij(x,y) << endl;
y=" << odejmij(x,y) << endl;
return 0;
}
Plik funkcja1.cpp:
#include iostream>
using namespace std;
std;
extern int a; //deklaracja zmiennej globalnej
//deklaracja zmiennej globalnej
//--------------------------
--------------------------
int dodaj(int a, int b)
a,
{
return a+b;
}
-------------------------
//-------------------------
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)) ;
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==1
7.4. Wstawianie innych plików
#include
#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
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),
" wskazników,
" innych tablic,
" z obiektów typu zdefiniowanego przez u\ytkownika,
" ze wskaznikó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
using namespace std;
int main()
{
int t[4];
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,-2 }; // 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
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 tab[i]=i;
dodaj2(tab,rozmiar);
for (i=0; i cout << "tab[" << i << "]=" << tab[i] << endl;
return 0;
}
//-------------------------------
void dodaj2(int tablica[], int ile)
{
int i;
for (i=0; i tablica[i] += 2;
}
Przykład :
#include
using namespace std;
#define ROZMIAR 4
void dodaj2(int tablica[ROZMIAR]);
//----------------------------
int main()
{
int tab[ROZMIAR];
Krzysztof Karbowski: Programowanie w języku C++ 30
int i;
for (i=0; i tab[i]=i;
dodaj2(tab);
for (i=0; 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 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
Aań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.
Krzysztof Karbowski: Programowanie w języku C++ 31
Przykład :
Temat: Funkcja kopiująca łańcuchy znakowe.
#include
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
#include
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;
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).
0 1
0 11 12
1 21 22
2 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 zle
9. Wskazniki
Wskaznik to obiekt do przechowywania informacji o adresie i typie
innego obiektu.
9.1. Definiowanie wskazników
int * w ; // w jest wskaznikiem do obiektów typu int
char * pLancuch;// pLancuch jest wskaznikiem do obiektow typu char
float * pWsk; // pWsk jest wskaznikiem do obiektow typu float
Zastosowanie wskazników:
" ulepszenie pracy z tablicami,
" funkcje mogące zmieniać wartość przysyłanych do nich argumentów,
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 wskaznikiem
Przykład :
#include
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;
}
Wskaznik do obiektu ka\dego niestałego typu mo\na przypisać
wskaznikowi typu void.
Krzysztof Karbowski: Programowanie w języku C++ 34
9.3. Zastosowanie wskaznikó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 wskaznika 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
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 wskaznikach
(wskaznik + liczba_całkowita) przesunięcie wskaznika o podaną liczbę elementów w przód,
(wskaznik liczba_całkowita) przesunięcie wskaznika o podaną liczbę elementów w tył,
(wskaznik wskaznik) gdy wskazniki pokazujÄ… na elementy tej samej tablicy to wynikiem
będzie liczba dzielących je elementów (liczba dodatnia lub ujemna).
9.5. Porównywanie wskazników
operator == równość wskazników oznacza, \e pokazują na ten sam obiekt,
operator != przeciwieństwo operatora ==,
Operatory mające zastosowanie do wskazników pokazujących na elementy tej samej tablicy:
Krzysztof Karbowski: Programowanie w języku C++ 35
> < >= <=
9.6. Zastosowanie wskazników w argumentach funkcji
Przykład :
#include
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 wskaznika
Przykład :
#include
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 cout << tab[i] << "\t";
}
//---------------------
void fkc_wsk1(int *wsk, int rozmiar)
{
cout << "\nPrzeslano jako wskaznik - wariant 1\n" ;
for (int i=0; i cout << *(wsk+i) << "\t";
}
//---------------------
void fkc_wsk2(int *wsk, int rozmiar)
Krzysztof Karbowski: Programowanie w języku C++ 36
{
cout << "\nPrzeslano jako wskaznik - wariant 2\n" ;
for (int i=0; i cout << wsk[i] << "\t";
}
9.6.2. Argument formalny będący wskaznikiem do obiektu const
Przykład:
void funkcja(const int *wsk, int rozmiar);
Wskaznik const pokazuje na obiekty, ale nie pozwala na ich modyfikacje.
Zastosowanie:
1. Zagwarantowanie, \e obiekt wysłany do funkcji poprzez wskaznik nie zostanie
zmieniony,
2. Umo\liwienie wysłania do funkcji poprzez wskaznik obiektu stałego (mo\na na niego
pokazać tylko wskaznikiem do stałej).
9.7. Zastosowanie wskazników przy dostępie do konkretnych
komórek pamięci
Przykład:
wsk = 0x0065fde8;
Wskaznikowi 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 wskaznika wsk. Operator delete zlikwiduje obiekt pokazywany
przez wskaznik 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:
Krzysztof Karbowski: Programowanie w języku C++ 37
" obiekty te nie mają nazwy dostęp do nich odbywa się poprzez wskaznik,
" 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 wskaznik pokazujący
na obiekt, to jest do niego dostęp.
Przykład :
#include
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 wsk1[i]=i*10;
cout << "Tablica:\n";
for (i=0; 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;
}
Wskazniki definiowane z modyfikatorem static inicjalizowane sÄ…
wartością NULL. Pozostałe wskazniki 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 wskazników
wsk = & obiekt;
wsk = inny_wskaznik;
wsk = tablica;
wsk = funkcja;
Krzysztof Karbowski: Programowanie w języku C++ 38
wsk = new int;
wsk = new float[10];
wsk = 0x82a5f2; // adres
wsk = "lancuch tekstowy";
9.10. Tablice wskazników
Przykład pięcioelementowa tablica wskazników do obiektów typu float:
float *tabwsk[5]; // inaczej: float *(tabwsk[5]);
Przykład tablice wskazników do stringów:
char *tab1[3];
char *tab2[3] = { "jeden", "dwa", "trzy" };
W tablicy tab2 znajdują się wskazniki do miejsc w pamięci, w których zlokalizowane są
poszczególne łańcuchy tekstowe.
Przykład :
#include
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)
{
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 {
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 {
(*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 cout << int(*(wsk+i)) << ',';
cout << endl;
}
9.11. Wskazniki do funkcji
Definicja:
int (*wsk_do_funkcji)(int, char);
oznacza, \e wsk_do_funkcji jest wskaznikiem 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
using namespace std;
int dodaj_dwa(int a);
int dodaj_trzy(int a);
int wywolaj(int (*wsk)(int), int liczba);
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
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);
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. Wskaznik 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 wskaznika i referencji do obiektu danej klasy:
nazwa_klasy * wsk ;
nazwa_klasy & refer = zmienna;
Krzysztof Karbowski: Programowanie w języku C++ 42
11.1. Składniki klasy
Dostęp do składników klasy:
" obiekt.składnik
" wskaznik -> składnik
" referencja.składnik
Przykład :
#include
#include
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
{
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
#include
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ń.
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
#include
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);
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
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 wskaznika 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
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.
Krzysztof Karbowski: Programowanie w języku C++ 47
12. Funkcje zaprzyjaznione
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ą wskaznika this do składników klasy, z którą są zaprzyjaznione, a
więc muszą posługiwać się operatorami . (kropka) lub ->.
Przykład :
#include
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
};
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.
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
#include
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);
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.
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
#include
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;
}
Krzysztof Karbowski: Programowanie w języku C++ 52
14.6. Konstrukcja obiektu, którego składnikiem jest obiekt innej
klasy
Przykład :
#include
#include
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];
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,
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;
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
#include
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");
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 <>---\n";
NapiszString(objWzorzec);
cout << "---Wywolaj <>---\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
#include
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);
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;
};
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
#include
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;
}
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
#include
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();
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 << "<>\n";
}
CZespol::CZespol(CLiczba objLiczba)
{
m_Real=objLiczba.m_Liczba;
m_Imag=0;
cout << "<>\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);
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
#include
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 << "<>\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;
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
#include
using namespace std;
//--------------------------
class CZespol
{
public:
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
#include
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)
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
#include
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()
{
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
#include
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;
}
//---------------------------
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
#include
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
{
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ć.
Krzysztof Karbowski: Programowanie w języku C++ 68
17.4. Operator wysyłania/pobierania danych do/z strumienia (<<, >>)
Przykład :
#include
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
Krzysztof Karbowski: Programowanie w języku C++ 69
{
Lista pochodzenia
//..............
};
class CKlasaPochodna : CKlasaPodstawowa
{
//...............
};
Przykład :
#include
#include
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,
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;
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
{
Odziedziczone
char m_sImie[80];
po COsoba
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.
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 klasa
podstawowa pochodna
private private
protected protected
public public
Dziedziczenie typu protected:
klasa klasa
podstawowa pochodna
private private
protected protected
public protected
Dziedziczenie typu private:
klasa klasa
podstawowa pochodna
private private
protected private
public private
18.2. WyjÄ…tki w dziedziczeniu
Nie dziedziczy siÄ™:
" konstruktorów
" operatora przypisania
" destruktora
składniki
składniki
składniki
składniki
składniki
składniki
Krzysztof Karbowski: Programowanie w języku C++ 73
18.3. Kolejność wywoływania konstruktorów
Przykład
#include
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;
}
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).
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
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;
}
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);
Krzysztof Karbowski: Programowanie w języku C++ 77
obj3=obj1;
return 0;
}
18.5. Konwersje standardowe przy dziedziczeniu
Wskaznik do obiektu klasy pochodnej mo\e być niejawnie przekształcony na wskaznik
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
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
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 wskaznika).
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 wskaznikami.
" przy zwracaniu przez funkcję rezultatu będącego referencją lub wskaznikiem.
Funkcja zdefiniowana jako zwracajÄ…ca referencjÄ™ (lub wskaznik) obiektu klasy
podstawowej mo\e zwracać referencję (lub wskaznik) 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 wskaznikami obiektów, a nie z samymi obiektami.
Obiekty klas pochodnych mogą być traktowane jako obiekty swych klas
podstawowych tylko podczas pracy na ich wskaznikach 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
}
Krzysztof Karbowski: Programowanie w języku C++ 79
Przykład
#include
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;
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ózne 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: wskaznik->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_
Krzysztof Karbowski: Programowanie w języku C++ 81
Plik Pracownik.cpp
#include
#include
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
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
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;
}
Wyszukiwarka
Podobne podstrony:
Języki programowania wykłady
Program wykładu Fizyka II 14 15
Makroekonomia program wykladu
INWENTARYZATOR informacje dla programistow v03 070329
11 Jezyki programowania Historia Przykładyid434
PiS15 W00k Program wykładów
Wykład 1 program wykładów W1 13 wprowadzenie
Egzamin z programowania (wyklad)
Woroniecka Program wykładów z ekonomii
Informacja dotyczÄ…ca programu
Program wykładów i ćwiczeń KTZ 2014
Informatyka Europejczyka Program nauczania informatyki w gimnazjum?ycja Mac OS 5 prongm
Program wykladu
Program wykładu 4 do samodzienego opracowania
rucki,języki programowania, język C
więcej podobnych podstron