Professional Documents
Culture Documents
1
LEKCJA 1. Co o C i C++ ka dy wiedzie powinien. * Jest najlepszy. Ostro niej - jest najch tniej stosowanym
narz dziem profesjonalnych programistów.
Ka dy PC jest w momencie zakupu (co cz sto wchodzi w cen zakupu Nauczywszy si j zyka C/C++ mo esz nie ba si ani systemu
komputera) wyposa any w system operacyjny DOS - np. DR DOS, PC UNIX/XENIX a ich rodowiska okienkowego - X Windows, ani OS2,
DOS, PTS DOS lub MS DOS. Standardowo w zestaw systemu MS DOS ani Windows 95 (dotychczasowe testy starych 16-bitowych
wchodzi interpreter j zyka BASIC (w MS-DOS - QBasic.EXE). Mo esz aplikacji wykazały b. wysoki stopie kompatibilno ci), ani
wi c by pewien, e je li jest DOS, to musi by i BASIC. stacji roboczych, ani du ych komputerów klasy mainframe. J zyk
Podobnie rzecz ma si z C/C++. Je li jest na komputerze system C/C++ dosłu ył si bowiem ogromnej ilo ci tzw. implementacji
UNIX (za wyj tkiem najubo szych wersji systemu XENIX), masz tam czyli swoich odmian, przeznaczonych dla ró nych komputerów i dla
do dyspozycji kompilator C/C++, za to BASICA ani Pascala prawie ró nych systemów operacyjnych. Windows NT i Windows 95 równie
na pewno tam nie ma. Podobnie coraz popularniejszy OS/2 zostały napisane w C++.
wyposa ony jest w kompilator (całkiem niezły) C++ i dodatkowo Czytaj c pras (np. Computer World, PC-Kurier i in.) zwró
jeszcze w pewne gotowe-firmowe biblioteki. uwag , e najwi cej ofert pracy jest wła nie dla programistów
posługuj cych si C++ (i tak zapewne b dzie jeszcze przez kilka
Grzech drugi: lat, póki nie wymy l czego lepszego - np. jakiego C+++).
* J zyk C/C++ powstał jeszcze zanim wymy lono PC, DOS, GUI Z Grzechu Trzeciego (cho nie tylko) wynika tak e po rednio
(Graficzny Interfejs U ytkownika), Windows i inne tym podobne. Grzech Czwarty.
Dwa najwa niejsze skutki praktyczne: J zyka C++ Grzech Czwarty - ANSI C, C++, czy Turbo C++, Visual
C++, czyli mała wie a BABEL.
I. W zało eniach twórców j zyk C++ miał by szybki (i jest) i
zajmowa mało miejsca w pami ci (bo ówczesne komputery miały jej Nie jestem pewien, czy "wie a BABEL" jest okre leniem
bardzo mało!). Zawiera wi c ró ne, niezrozumiałe dla nas z trafniejszym ni "kamie filozoficzny", b d "perpetuum mobile".
dzisiejszego punktu widzenia skróty. Np. to co w Pascalu czy To co w ci gu ostatnich lat stało si z j zykiem C++ ma co
Basicu wygl da zrozumiale: wspólnego z ka dym z tych utopijnych symboli. A w du ym
uproszczeniu było to tak.
i:=i+1; (Pascal)
10 I=I+1 lub inaczej NEXT I (Basic) Podobnie, jak mechanikom od zarania dziejów marzyło si
perpetuum mobile, tak informatykom zawsze marzyło si stworzenie
to w j zyku C++ wygl da dziwacznie: jednego SUPER-UNIWERSALNEGO j zyka programowania. Takiego, który
byłby zupełnie niezale ny od sprz tu tzn., aby program napisany
i++; albo jeszcze dziwniej ++i; w takim j zyku mógł by przeniesiony BEZ ADNYCH ZMIAN na
dowolny komputer I DZIAŁAŁ. Do takiej roli pretendowały kolejno
Tym niemniej zwró uwag , e w Pascalu zajmuje to 7 znaków, w FORTRAN, Algol a potem przyszła pora na C/C++. Gdyby informatycy
Basicu - 8 znaków (spacja to te znak!), a w C++ tylko 4. nie okazali si zbyt zachłanni, mo e co by z tego wyszło. Ale,
jak to w yciu, programi ci (podobnie jak ona rybaka z bajki "O
Inny przykład: rybaku i złotej rybce") chcieli wszystkiego naraz:
X=X+5 (Basic, 5 znaków), * eby program dał si przenie na komputer innego typu i
X:=X+5 (Pascal, 6 znaków), działał,
X+=5 (C++, tylko 4 znaki). * eby działał szybko i optymalnie wykorzystywał sprz t,
* eby umiał wszystko, co w informatyce tylko wymy lono (tj. i
Z takiej wła nie filozofii wynika i sama nazwa - najkrótsza z grafika, i obiekty, i obsługa peryferii i...).
mo liwych. Je li bowiem i++ miało znaczy mniej wi cej tyle samo
co NEXT I (nast pne I) to C++ znaczy mniej wi cej tyle samo co I stało si . W pomy lanym jako uniwersalny j zyku zacz ły
"NAST PNA WERSJA C". powstawa odmiany, dialekty, mutacje, wersje itp. itd.
II. Nie ma nic za darmo. W j zyku C/C++, podobnie jak w Je li C++ nie jest Twoim pierwszym j zykiem, z pewno ci
samochodzie wy cigowym formuły I, za szybko i skuteczno zauwa yłe Czytelniku, e pomi dzy GW Basic a Quick Basic s
płaci si komfortem. Konstrukcje stosowane w j zyku C/C++ s pewne drobne ró nice. Podobnie Turbo Pascal 7.0 troch ró ni si
maksymalnie dostosowane do "wygody" komputera. Pozwala to na od Turbo Pascala 5.0. Mimo to przykład poni ej pewnie Ci troch
uzyskiwanie ˙niezwykle szybkich "maszynowo-zorientowanych" kodów zaskoczy. Dla zilustrowania skali problemu przedstawiam poni ej
wykonywalnych programu, ale od programisty wymaga dwie wersje TEGO SAMEGO PROGRAMU napisanego w dwu ró nych
przyzwyczajenia si do "komputerowo-zorientowanego sposobu wersjach TEGO SAMEGO J ZYKA C++. . Obydwa programy robi
my lenia". dokładnie to samo. Maj za zadanie wypisa na ekranie napis
"Hello World" (czyli "Cze wiecie!").
Grzech Trzeci (i chyba najci szy):
2
Program (1)
Ameryka ski Instytut Standardów ANSI od lat prowadzi walk z
main() wiatrakami. Stoi na stra y jednolitego standardu j zyka, który
{ nazywa si standardem ANSI C i ANSI C++. Wielcy producenci od
printf("Hello World\n"); czasu do czasu organizuj konferencje i spotkania gdzie w
} ciepłych krajach i uzgadniaj niektóre standardy - czyli wspólne
dla nich i zalecane dla innych normy, ale niektórzy bywaj
zazdro ni o własne tajemnice i nie publikuj wszystkich
Program (2) informacji o swoich produktach. Dlatego wszelkie "słuszne i
uniwersalne" standardy typu ODBC, Latin 2, Mazovia, LIM, OLE,
#include <windows.h> DDE, BGI, itp., itd. maj niestety do dzi ograniczony zakres
#include <iostream.h> stosowalno ci a wszelkie zapewnienia producentów o całkowitej
zgodno ci ich produktu z... (tu wpisa odpowiednie) nale y
LPSTR p = "Hello World\n"; niestety nadal traktowa z pewn rezerw .
Poniewa plik kompilatora nie mie ci si w 640 K pami ci musi [S!] GRUPY POLECE - NAZWY POSZCZEGÓLNYCH
dokonywa tzw. SWAPOWANIA i tworzy na dysku dodatkowy plik "ROZWIJANYCH" MENU.
tymczasowy (ang. swap file). Na dysku roboczym powinno
pozostawa najmniej 500 KB wolnego miejsca. Je li mo esz, = Bez nazwy (menu systemowe).
pozostaw na tym dysku wolne nie mniej ni 1 MB. Ułatwi to i File Operacje na plikach.
przyspieszy prac . Edit Edycja plików z tekstami ródłowymi programów.
________________________________________________________________ Search Przeszukiwanie.
Run Uruchomienie programu.
Tworzony tymczasowo plik roboczy wygl da tak: Compile Kompilacja programu.
Debug "Odpluskwianie", czyli wyszukiwanie bł dów w
Volume in drive D has no label programie.
Directory of D:\SIERRA Project Tworzenie du ych, wielomodułowych programów.
Options Opcje, warianty IDE i kompilatora.
TC000A SWP 262144 12-13-94 5:42p (13-XII to dzi !) Window Okna (te na ekranie).
1 file(s) 262144 bytes Help Pomoc, niestety po angielsku.
11696320 bytes free
UWAGA:
[!!!] UWAGA: __________________________________________________________
W niektórych wersjach kompilatora na pasku głównego menu pojawi
Kompilator C++ b dzie próbował tworzy plik tymczasowy zawsze w si jeszcze Browse - przegl danie (funkcji, struktury klas i
bie cym katalogu, tzn. tym, z którego wydałe rozkaz obiektów). Zwró uwag , e w okienkowych wersjach niektóre
TC lub BC. rozkazy "zmieniaj " menu i trafiaj do
Browse, Debug, Project.
II. WNIOSKI PRAKTYCZNE. W BC++ 4 menu Run brak (!). Tworzenie aplikacji sprowadza si
tam do nast puj cych kroków:
* Lepiej nie uruchamia C++ "siedz c" na dyskietce, poniewa
mo e mu tam zabrakn miejsca na plik tymczasowy. Project | Open project lub | AppExpert
* Dla u ytkowników Novella: Uruchamiajcie kompilator C++ tylko Debug | Run
we własnych katalogach - do innych mo ecie nie mie praw zapisu.
Plik .SWP jest tworzony tylko podczas sesji z kompilatorem C++ i ROZWIJAMY MENU.
usuwany natychmiast po jej zako czeniu. Mo esz go zobaczy tylko Z takiego kr cenia si w kółko po pasku (a propos, czy
zauwa yłe , e pasek pod wietlenia mo e by "przewijany w
wychodz c "na chwil " do systemu DOS przy pomocy rozkazu DOS kółko"?) jeszcze niewiele wynika. Robimy wi c nast pny krok.
Shell (menu File).
Wska w menu głównym nazw "File" i naci nij [Enter].
[S!] SWAP - Zamiana. Rozwin ło si menu File zawieraj ce list rozkazów dotycz cych
________________________________________________________________ operacji na plikach. Po tym menu te mo esz si porusza przy
Je li wszystkie dane, potrzebne do pracy programu nie mieszcz pomocy klawiszy kursora ze strzałkami gór lub w dół. Masz do
si jednocze nie w pami ci operacyjnej komputera, to program - wyboru dwie grupy rozkazów rozdzielone poziom lini :
"wła ciciel", (lub system operacyjny - DOS, OS2, Windows) mo e
dokona tzw. SWAPOWANIA. Polega to na usuni ciu z pami ci [S!]
operacyjnej i zapisaniu na dysk zb dnej w tym momencie cz ci ______________________________________________________________
danych, a na ich miejsce wpisaniu odczytanej z dysku innej Open - Otwórz istniej cy ju plik z programem (np. w celu
cz ci danych, zwykle takich, które s programowi pilnie dopisania czego nowego).
5
New - Utwórz nowy plik (zaczynamy tworzy nowy program). zamiast napisu
Save - Zapisz bie cy program na dysk. Pami taj: Pliki z
dysku nie znikaj po wył czeniu komputera. Zawsze "NONAME00.CPP" (ang. no mame - bez nazwy)
lepiej mie o jedn kopi za du o ni o jedn za mało.
jest teraz nazwa Twojego programu - PIERWSZY.CPP. Kursor miga w lewym
oraz górnym rogu okna edytora. Mo emy zaczyna .
Print - Wydrukuj program.
Get Info - Wy wietl informacje o stanie IDE. Pierwsze podej cie do programu zrobimy troch "intuicyjnie".
Dos Shell - Wyj cie "na chwil " do systemu DOS z mo liwo ci Zamiast wyja nia wszystkie szczegóły posłu ymy si analogi do
powrotu do IDE przez rozkaz EXIT. konstrukcji w Pascalu i Basicu (zakładam, e napisałe ju
Quit - Wyj cie z IDE Turbo C++ i powrót do DOSa. Inaczej - cho by jeden program w którym z tych j zyków). Szczegóły te
KONIEC PRACY. wyja ni dokładniej pocz wszy od nast pnej lekcji.
_______________________________________________________________
Skoro ju wiemy jak rozpocz prac nad nowym programem, WPISUJEMY PROGRAM "PIERWSZY.CPP".
zacznijmy przygotowanie do uruchomienia naszego pierwszego
programu. Wpisz nast puj cy tekst programu:
Wybierz z menu File rozkaz Open... (otwórz plik). Poniewa /* Program przykładowy - [P-1] */
rozkaz taki jest niejednoznaczny, wymaga przed wykonaniem
podania dodatkowych informacji. Gdyby Twój komputer mówił, #include <stdio.h>
zapytałby w tym momencie "który plik mam otworzy ?". Pytanie main()
zada musi, b dzie wi c prowadził dialog z Tob przy pomocy {
OKIENEK DIALOGOWYCH. Je li wybrałe z menu rozkaz OPEN i printf("Autor: ..........."); /*tu wpisz imie Twoje!*/
nacisn łe [Enter], to masz wła nie na ekranie takie okienko printf(" TO JA, TWOJ PROGRAM - PIERWSZY.CPP");
dialogowe. Okienko składa si z kilku charakterystycznych printf("...achoj !!!");
elementów: }
OKIENKO TEKSTOWE - (ang. Text Box lub Input Box) w którym mo esz I ju . Jak widzisz nie jest to a takie straszne. Gdyby nie to,
e zamiast znajomego PRINT"TO JA...", albo writeln(".."); jest
pisa (klawisz BackSpace [<-] pozwoli Ci printf("...");, byłoby prawie całkiem zrozumiałe. Podobny
skasowa wprowadzony tekst, je li si program w Pascalu mógłby wygl da np. tak:
rozmy lisz). Okienko to zawiera tekst "*.C".
# include <stdio.h> uses Crt;
OKIENKO Z LIST - (ang. List Box) zawiera list plików, z której main() /* pocz tek */ program AHOJ; {pocz tek}
mo esz wybra plik z programem. { Begin
printf("Autor"); write('Autor');
KLAWISZE OPCJI/POLECE - (ang. Command Button) kiedy ju printf("TO JA"); write('TO JA');
dokonasz wyboru, to mo esz wskazuj c printf("ahoj"); write('ahoj');
taki klawisz np. potwierdzi [OK], } end.
zrezygnowa [Cancel], otworzy plik
[Open] itp..
a w BASICU:
Pomi dzy elementami okienka dialogowego mo esz porusza si przy
pomocy klawiszy kursora i klawisza [Tab] lub kombinacji klawiszy 10 PRINT "Autor" : REM Pocz tek
20 PRINT "TO JA"
[Shift]-[Tab] (spróbuj!). 30 PRINT "ahoj"
40 END
Mo esz tak e posługiwa si myszk .
Wi cej o okienkach i menu dowiesz si z nast pnych lekcji, a na
razie wró my do naszego podstawowego zadania - tworzenia [!!!]UWAGA
pierwszego programu. ______________________________________________________________
Zwró uwag , e działanie funkcji:
Zanim zaczniemy tworzy program włó do kieszeni nap du A: (lub PRINT (Basic),
B:) dyskietk doł czon do niniejszej ksi ki. Mo e ona sta si printf() (C++),
Twoj dyskietk robocz i pomocnicz zarazem na okres tego Write i Writeln (Pascal)
kursu. nie jest identyczne, a TYLKO PODOBNE.
________________________________________________________________
Je eli zainstalowałe zawarto dyskietki na dysku - przejd do
stosownego katalogu - C:\C-BELFER (D:\C-BELFER) i odszukaj tam Sprawdzimy, czy program działa. Tam, gdzie s kropki wpisz Twoje
programy przykładowe. Je li nie - mo esz nadal korzysta z imi - np. Ewa, Marian, Marcin. Pami taj o postawieniu na ko cu
dyskietki (jest na niej troch miejsca). znaków cudzysłowu ("), zamkni ciu nawiasu i redniku (;) na
ko cu linii (wiersza).
Wpisz do okienka tekstowego nazw A:\PIERWSZY (lub odpowiednio
np. C:\C-BELFER\PIERWSZY). Rozszerzeniem mo esz si nie Naci nij kombinacj klawiszy [Alt]-[R]. Jest to inny, ni
przejmowa - zostanie nadane automatycznie. Plik roboczy z Twoim opisano poprzednio sposób dost pu do menu. Kombinacja klawiszy
programem zostanie utworzony na dyskietce w nap dzie A:. [Alt]-[Litera] powoduje uaktywnienie tego menu, którego nazwa
zaczyna si na podan liter . Przy takiej konwencji litera nie
Wska klawisz [Open] w okienku dialogowym i naci nij [Enter] na musi by zawsze pierwsz liter nazwy opcji. Mo e to by tak e
klawiaturze. litera wyró niona w nazwie przez podkre lenie lub wy wietlenie
np. w innym kolorze. I tak:
UWAGA!
________________________________________________________________ [Alt]+[F] menu File (Plik)
_ [Alt]+[C] menu Compile (Kompilacja
Dopóki manipulujesz okienkiem tekstowym i okienkiem z list [Alt]+[R] menu Run (Uruchamianie)
klawisz polecenia [Open] jest wyró niony (pod wietlony) i [Alt]+[W] menu Window (Okna)
traktowany jako tzw. OPCJA DOMY LNA (ang. default). W tym itd., itd..
stadium aby wybra [Open] WYSTARCZY NACISN [Enter].
________________________________________________________________ Kombinacja [Alt]+[R] wybiera wi c menu Run (uruchomienie
__ programu). Menu Run daje Ci do wyboru nast puj ce polecenia:
[S!]
Wrócili my do IDE. zmieniło si tyle, e w nagłówku okna edytora ________________________________________________________________
6
Run - Uruchomienie programu (Utwórz plik .EXE i Wykonaj). *WARNING A:\PIERWSZY.C 4: Function should return a value in
Program Reset - "Wyzerowanie" zmiennych programu. function main
Go to Cursor - Wykonanie programu do miejsca wskazanego kursorem
w tek cie. (Uwaga: Funkcja main powinna zwróci warto .)
Trace Into - Uruchom ledzenie programu.
Step Over - ledzenie programu z mo liwo ci pomini cia funkcji. Na razie zadowolimy si spostrze eniem, e:
* Bł dy UNIEMO LIWIAJ KOMPILACJ i powoduj komunikat
(dosł. tzw. "Przekraczanie" funkcji). ERRORS.
Arguments - Uruchom program z zadanymi argumentami. * Ostrze enia NIE WSTRZYMUJ KOMPILACJI i powoduj komunikat
________________________________________________________________ WARNINGS.
Wybierz "Run". Je li nie zrobiłe adnego bł du, program Jaki jest sens powy szego ostrze enia i jak go unikn dowiesz
powinien si skompilowa z komentarzem "Success" i wykona si z nast pnych lekcji.
(kompilacja zako czona sukcesem; napis mignie tak szybko, e ________________________________________________________________
mo esz tego nie zauwa y ). Je li chcesz spokojnie obejrze
wyniki działania swojego programu powiniene wykona Pozostaje nam w ramach tej lekcji:
nast puj ce czynno ci: * Zapisa Twój pierwszy program na dysku i
* Wyj z IDE C++.
1. Rozwi menu Window naciskaj c klawisze [Alt]-[W].
2. Wybierz z menu rozkaz User screen (ekran u ytkownika). JAK ST D WYJ ?
Mo esz wykona to samo bez rozwijania menu naciskaj c kombinacj
Aby zapisa plik PIERWSZY.CPP z Twoim programem (ko cow
klawiszy [Alt]-[F5]. ostateczn wersj ) na dysk nale y wykona nast puj ce czynno ci:
3. Po przejrzeniu wydruku naci nij [Enter]. Wrócisz do okna
edytora. 1. Naci nij klawisz [F10].
W głównym menu pojawi si pasek wyró nienia sygnalizuj c, e
Je li zrobiłe bł dy - kompilacja si nie uda i program nie menu stało si aktywne.
zostanie wykonany, w okienku natomiast pojawi si napis "Errors"
2. Naci nij klawisz [F].
(czyli "Bł dy"). Je li tak si stało naci nij [Enter] Pasek wyró nienia przesunie si pod wietlaj c menu File
dwukrotnie. Popraw ewentualne niezgodno ci i spróbuj jeszcze (operacje na plikach). Rozwinie si menu File.
raz.
3. Naci nij klawisz [S] - wybierz polecenie Save (je li chcesz
Bł dów zwykle bywa nie wi cej ni dwa. Najcz ciej jest to brak zapisa program w bie cym katalogu i pod bie c nazw ) lub
lub przekłamanie której litery (w słowie main lub printf) i rozkaz Save As... (zapisz jako...), podaj nowy dysk/katalog i
brak rednika na ko cu linii. W okienku komunikatów (Message) now nazw pliku.
mog pojawi si napisy - np.:
Tekst Twojego programu został zapisany na dysku/dyskietce. Teraz
Error: Statement missing ;
(Bł d: Zgubiony znak ;) mo emy wyj z C++.
[S] Error Messages - Komunikaty o bł dach. Aby to zrobi , wykonaj nast puj ce czynno ci:
________________________________________________________________
Najcz ciej w komunikatach o bł dach b d na pocz tku pojawia 1. Naci nij klawisz [F10]. Uaktywni si główne menu.
si nast puj ce słowa: 2. Rozwi menu File naciskaj c klawisz [F].
3. Wybierz z menu polecenie "Exit/Quit" i naci nij [Enter].
Error - bł d
Warning - ostrze enie [!!!] SAVE szybciej.
Syntax - składnia (składniowy) ________________________________________________________________
Expression - wyra enie Zwróc uwag , e zamiast rozwija kolejne menu, mo esz korzysta
never used - nie u yte (nie zastosowane) z kombinacji klawiszy, które pozwalaj Ci wyda rozkaz bez
assign - przypisywa , nadawa warto /znaczenie rozwijania menu. Takie kombinacje klawiszy (ang. hot keys lub
value - warto shortcut keys) znajdziesz w menu obok rozkazu, np.:
statement - operator, operacja, wyra enie
________________________________________________________________ [Alt]-[X] - Quit/Exit
[F2] - Save
[???] Co z tym rednikiem? [F3] - Open
[Alt]-[F5] - User screen (Podgl danie działania programu) itp.
________________________________________________________________ ________________________________________________________________
Zwró uwag , e po pd wietleniu komunikatu o bł dzie (pasek
wyró nienia pod wietlenia mo esz przesuwa po li cie przy pomocy [Z]
klawiszy ze strzałkami w gór i w dół) i po naci ni ciu [Entera] ________________________________________________________________
kompilator poka e ten wiersz programu, w którym jego zdaniem 1. Spróbuj napisa i uruchomi kilka własnych programów
jest co nie w porz dku. Brak rednika zauwa a zwykle dopiero po wypisuj cych ró ne napisy. W swoich programach zastosuj funkcj
przej ciu do nast pnego wiersza (i ten e wiersz poka e), co bywa printf() według nast puj cego wzoru:
na pocz tku troch myl ce.
________________________________________________________________ printf("....tu wpisz napis do wydrukowania...");
* w OKIENKU KOMPILACJI: (bardzo typowa sytuacja) Swoim programom staraj si nadawa łatwe do rozpoznania nazwy
typu PIERWSZY, DRUGI, ADAM1, PRZYKLAD itp.
Errors: 0 (Bł dy: 0)
Warnings: 1 (Ostrze enia: 1) [???] NIE CHCE DZIAŁA ?
________________________________________________________________
Pami taj, e dla j zyka C i C++ (w przeciwie stwie np. do
* W OKIENKU KOMUNIKATÓW - (Messages - tym w dolnej cz ci Basica) PRINTF i printf to nie to samo! Słowa kluczowe i nazwy
ekranu): standardowych funkcji
MUSZ BY PISANE MAŁYMI LITERAMI !!!
7
________________________________________________________________ Alt+H Rozwini cie menu Help (pomoc)
Alt+B Rozwini cie menu przegl darki - Browse (Win)
[???] GDZIE MOJE PROGRAMY ? Alt+X Wyj cie z kompilatora DOS'owskiego - Exit
________________________________________________________________ Alt+F4 Wyj cie z kompilatora dla Windows
B d spokojny. Zapisz wersje ródłowe programów na dyskietk ________________________________________________________________
(dysk). Swoje programy skompilowane do wykonywalnej wersji *.EXE
znajdziesz najprawdopodobniej w katalogu głównym tego dysku, na
którym zainstalowany został C++ lub w katalogu Rozkazy w trybie edycji tekstu programu:
\BORLANDC\BIN\.... Je li ich tam nie ma, zachowaj zimn krew i ________________________________________________________________
przeczytaj uwa nie kilka nast pnych stron. Shift+Delete Wytnij wybrany blok tekstu (Cut) i umie w
________________________________________________________________ przechowalni (Clipboard)
Shift+Insert Wstaw blok tekstu z przechowalni (Paste)
Ctrl+Insert Skopiuj zaznaczony blok tekstu do przechowalni
PAMI TAJ: (Copy)
________________________________________________________________ Ctrl+Y Skasuj wiersz tekstu (Delete a line)
Je li masz oryginalny tekst programu, nazywany WERSJ RÓDŁOW Ctrl+Delete Skasuj zaznaczony blok tekstu
PROGRAMU, zawsze mo esz uzyska ten program w wersji "roboczej", Shift+[-->] Zaznaczanie bloku tekstu w prawo
tzn. skompilowa go na plik wykonywalny typu *.EXE (ang. Shift+[<--] Zaznaczanie bloku tekstu w lewo
EXEcutable - wykonywalny). Shift+[Down Arrow] Zaznaczanie bloku tekstu w dół (strzałka w
________________________________________________________________ dół)
Shift+[Up Arrow] Zaznaczanie bloku tekstu w gór (strzałka w
gór )
[S!] printf() - PRINTing Function - Funkcja DRUKuj ca Alt+Backspace Anuluj ostatni operacj (Undo)
________________________________________________________________ Ctrl+L Powtórz przeszukiwanie (Repeat search)
na ekranie (dokładniej - na standardowym urz dzeniu wyj cia). ________________________________________________________________
Odpowiednik PRINT w Basicu lub write w Pascalu. Dla ułatwienia
rozpoznawania nazw funkcji w tek cie wi kszo autorów pisz ca o
j zyku C++ umieszcza zawsze po nazwie funkcji par nawiasów (tak Rozkazy ogólnego przeznaczenia:
te musi j stosowa programista w programach w C++). Ja tak e ________________________________________________________________
b d stosowa dalej t zasad . F1 Wy wietl pomoc - Help screen
________________________________________________________________ F2 Zapisz bie cy stan tekstu na dysk (Save)
F3 Otwórz nowy plik (Open)
F4 Uruchom i wykonaj program do pozycji wskazanej
[???] A JE LI NIE MA C++ ??? kursorem
________________________________________________________________ F5 Powi ksz (maximize) bie ce aktywne okno
W przeciwie stwie do INTERPRETERÓW (np. QBasic), które musz by F6 Przejd do nast pnego okna (next window)
obecne, by program zadziałał, KOMPILATORY tworz wersje F7 Wykonaj program krok-po-kroku
wykonywalne programów, które mog pracowa niezale nie. W F8 Wykonaj program krok-po-kroku z pomini ciem
katalogu głównym tego dysku, na którym jest zainstalowany Twój ledzenia funkcji
BORLAND/Turbo C++ znajdziesz swoje programy PIERWSZY.EXE, F9 Skompiluj i skonsoliduj program (Compile/Make)
DRUGI.EXE itp. Aby te programy uruchomi nie musisz uruchamia F10 Uaktywnij pasek głównego menu
kompilatora C++. Wystarczy: Shift+F1 Wy wietl spis tre ci Help - tzw. Help index
Shift+F2 Wybierz rozkaz Arguments... z menu Run
1. Przej na odpowiedni dysk przy pomocy polecenia: (uruchamianie programu z parametrami w
D: (E: lub F:) DOS'owskim wierszu rozkazu)
Ctrl+F1 Podpowiedzi kontekstowe (help topic search)
2. Przej do odpowiedniego katalogu - np. głównego: Ctrl+F2 Wyzeruj bie cy program
CD \ Ctrl+F5 Zmie pozycj aktywnego okna
Ctrl+F7 Wy wietl okienko dialogowe "Add Watch"
3. Wyda polecenie: Ctrl+F8 Zaznacz punkt krytyczny (Toggle breakpoint)
PIERWSZY[Enter] Ctrl+F9 Uruchom program (Run)
________________________________________________________________ Ctrl+PgUp Skocz na pocz tek pliku
Ctrl+PgDn Skocz na koniec pliku
[!!!]UWAGA: Alt+F1 Poka poprzedni ekran Help
________________________________________________________________ Alt+F2 Zmniejsz okno
Je li nie jeste jedynym u ytkownikiem kompilatora C++ i na tym Alt+F3 Zamknij aktywne okno
samym komputerze pracuje jeszcze kto inny, sprawd , czy inny Alt+F4 Dokonaj inspekcji (inspect)
u ytkownik nie ustawił inaczej katalogu wyj ciowego (Options | Alt+F5 Poka DOS'owski ekran roboczy (User screen)
Directories | Output Directory). Katalog wyj ciowy (ang. output Alt+F7 Przejd do poprzedniego bł du (previous error)
directory) to ten katalog, w którym C++ zapisuje pliki *.EXE po Alt+F8 Przejd do nast pnego bł du (next error)
wykonaniu kompilacji. Je li jeste skazany na własne siły - ________________________________________________________________
patrz - nast pne lekcje.
________________________________________________________________ ________________________________________________________________
EOF
W trakcie uruchamiania kompilator korzysta z plików [S] ACTIVE WINDOW - AKTYWNE OKNO.
zewn trznych. C++ stara si by USER FRIENDLY (przyjazny wobec ________________________________________________________________
u ytkownika) i odtworzy taki stan ekranu, w jakim ostatnio Na ekranie mo e si znajdowa jednocze nie wiele okien, ale w
przerwałe prac , co nie zawsze jednak jest korzystne. W wierszu danym momencie tylko jedno z nich mo e by AKTYWNE. Aktywne
okno, to to, w którym miga kursor i w którym aktualnie
statusowym pojawiaj si napisy informuj ce o tym (np: pracujesz. Aktywne okno jest dodatkowo wyró nione podwójn
ramk .
Loading Desktop File . . . ________________________________________________________________
* zmieni nazw pliku [D:]\BORLANDC\BIN\TCDEF.DSK Zwró uwag , e dopóki bie cym aktywnym oknem jest okienko
komunikatów (Message - to w dolnej cz ci ekranu), nie mo esz
na dowoln inn , np. STARY.DSK lub STARY1.DSK, stosuj c np. powtórzy kompilacji programu. Rozkazy Compile | Compile i
polecenie systemu DOS RENAME. [D:] oznacza odpowiedni dla Run | Run b d "zrobione na szaro" (ang. grayed out) - czyli
Twojego komputera dysk. C++ wystartuje wtedy z czystym ekranem i nieaktywne. Najpierw trzeba przej do okna edycji tekstu
programu (np. poprzez klikni cie myszk ).
utworzy nowy plik TCDEF.DSK. ________________________________________________________________
Aby zamkn zb dne okna mo esz zastosowa równie rozkaz Close [Alt]+[O]
(ang. Close - zamknij) z menu Window (okna). Zwró uwag , e
polecenie Close odnosi si do bie cego okna wyró nionego przy Rozwin ło si menu, udost pniaj c nast puj c list polece :
pomocy podwójnej ramki. Aby zamkn bie ce okno, powiniene :
FULL MENUs - Pełne Menu ("s" oznacza, e chodzi o "te" menu w
1. Nacisn klawisze [Alt]-[W] liczbie mnogiej, a nie o pojedyncze menu).
Rozwinie si menu Windows. COMPILER - Kompilator.
2. Wybra z menu rozkaz Close - [C]. MAKE... - dosł. "ZRÓB", dotyczy tworzenia "projektów" (zwró
uwag na wielokropek [...]).
Mo e pojawi si okienko z ostrze eniem: DIRECTORIES... - KATALOGI (znów wielokropek !).
ENVIRONMENT... - OTOCZENIE lub inaczej RODOWISKO.
WARNING: A:\PIERWSZY.CPP not saved. Save? SAVE - ZAPAMI TAJ (UWAGA: To jest zupełnie inne SAVE ni
(UWAGA: plik A:\PIERWSZY.CPP nie zapisany na dysku. Zapisa ?). w menu File. Nie wolno myli tych polece .
Pomyłka grozi utrat tekstu programu!).
9
________________________________________________________________
Popatrz na lini statusow . Je li b dziesz porusza si po menu * Je li zainstalowałe zawarto dyskietki na dysku i wolisz
Option, pod wietlaj c kolejne rozkazy, w wierszu statusowym posługiwa si własnym katalogiem roboczym - wpisz tam
b dzie wy wietlany krótki opis działania wskazanego rozkazu. I odpowiedni cie k dost pu - np. C:\C-BELFER. Je li Twój
tak, powiniene zobaczy kolejno nast puj ce napisy: katalog zagnie d ony jest gł biej (np. w przypadku u ytkowników
sieci Novell) - podaj pełn cie k dost pu - np.:
Full Menus [Off/On]- Use or don't use full set of menu commands. F:\USERS\ADAM\C-BELFER
* Wsz dzie, gdzie w tre ci ksi ki odwołuj si do dyskietki A:
(Stosuj lub nie stosuj pełnego zestawu rozkazów w menu - mo esz konsekwentnie po zainstalowaniu stosowa odpowiedni
domy lnie przyjmowane jest Off/Nie). katalog na dysku stałym, b d na dysku sieciowym.
________________________________________________________________
Compiler - Set compiler defaults for code generation, error
messages and names. 4. Naci nij [Enter].
(Ustaw domy lne parametry pracy kompilatora dotycz ce Spróbuj teraz, znan z poprzedniej lekcji metod , wczyta do
generowania kodu programu, komunikatów o bł dach i nazw). okienka edytora Twój pierwszy program. Musisz wykona
nast puj ce czynno ci:
Make... - Set condition for project-makes.
(Ustawianie warunków do tworzenia projektu). 1. Włó do nap du A: dyskietk z programem PIERWSZY.CPP (je li
jeszcze jej tam nie ma).
Directories... - Set path for compile, link and executable 2. Rozwi menu File, naciskaj c kombinacj klawiszy [Alt]-[F].
files. 3. Wybierz z menu rozkaz Open, naciskaj c klawisz [O].
(Wybierz katalogi i ustaw cie ki dost pu dla kompilacji, Pojawi si znane Ci okienko dialogowe. Zwró uwag na wiersz
konsolidacji i WSKA MIEJSCE - GDZIE ZAPISA PLIK TYPU *.EXE po statusowy. Napis:
kompilacji).
Enter directory path and file mask
Environment... - Make environment wide settings (eg, mouse znaczy:
settings). Wpisz cie k dost pu do katalogu i "wzorzec" nazwy pliku.
(Ustawienie parametrów rozszerzonego otoczenia, np. parametrów
pracy myszki). U yte słowo "wzorzec" oznacza, e wolno Ci wpisa do okienka
tekstowego tak e nazwy wieloznaczne, zawieraj ce znaki "*" i
Save - Save all the settings you've made in the Options menu. "?", np.:
Ten rozkaz pozwala Ci ustawi konfiguracj IDE "raz na zawsze". itp. (Spróbuj!, zawsze mo esz si wycofa lub zmieni zdanie,
posługuj c si klawiszami [BackSpace], [Shift], [Tab] i [Esc].).
Przygotujmy si do powtórzenia kompilacji programu PIERWSZY.CPP.
Klawisz [Tab] umo liwia Ci skok od okienka do okienka "do
Je li masz na ekranie rozwini te menu Options, wybierz z menu przodu", a [Shift]-[Tab] - "do tyłu". Zgodnie z nazw (ang.
polecenie Directories... . ESCape - ucieka ), klawisz [Esc] pozwala Ci wycofa si z
niewygodnych sytuacji - np. zamkn okienko dialogowe lub zwin
KOMPILACJA ZE WSKAZANIEM ADERSU. rozwini te menu bez adnej akcji.
1. Wska w menu polecenie Directories i naci nij [Enter]. Je li wpiszesz wzorzec nazwy, to w okienku z list zobaczysz
Po poleceniu umieszczony jest wielokropek. Znaczy to, e rozkaz wszystkie pliki wybrane z podanego dysku i z podanego katalogu
nie zostanie wykonany, zanim komputer nie uzyska od Ciebie według zadanego wzorca. Aby wybra plik z listy nale y klawiszem
pewnych dodatkowych informacji. Wiesz ju , e praktycznie
oznacza to dla Ciebie konieczno "wypełnienia" okienka [Tab] przej do okienka z list , klawiszami kursora wskaza
dialogowego. Po wybraniu polecenia Directories ukazało si potrzebny plik i nacisn [Enter].
okienko dialogowe ju "wst pnie wypełnione". Takie "wst pne
wypełnienie" okienka daje Ci pewne dodatkowe informacje. Wynika 4. Wpisz do okienka tekstowego
z niego mianowicie JAKIE PARAMETRY S PRZYJMOWANE A:\PIERWSZY.CPP
DOMY LNIE 5. Naci nij [Enter].
(default).
[!!!]FAST START - SZYBKI START.
W okienku dialogowym masz trzy okienka tekstowe: ________________________________________________________________
Je li chcesz by C++ automatycznie wczytał Twój program do
* Include Directories (Katalog zawieraj cy pliki nagłówkowe, np. okienka edytora, to mo esz zada nazw pliku z tekstem programu
jako parametr w wierszu polecenia, uruchamiaj c C++ np. tak:
STDIO.H, CONIO.H, GRAPHICS.H itp. doł czane do programów).
BC A:\PIERWSZY.CPP
* Library Directories (Katalog zawieraj cy gotowe biblioteki,
zawarte w plikach typu *.LIB,). Je li korzystasz z programu Norton Commander, to mo esz doda do
* Output Directory (Katalog wyj ciowy, w którym po kompilacji pliku NC.EXT nast puj cy wiersz:
b d umieszczane Twoje programy w wersji *.EXE).
C: TC !.!
Pierwsze dwa zostawimy w spokoju. cpp: bc !.!
2. Naci nij dwukrotnie klawisz [Tab]. Kursor wskazuje teraz wówczas wystarczy tylko wskaza odpowiedni plik typu *.C lub
okienko tekstowe Output Directory. .CPP z tekstem programu i nacisn [Enter].
________________________________________________________________
3. Wpisz do okienka tekstowego Output Directory:
A:\ lub C:\C-BELFER Kompilatory Borlanda mog w ró nych wersjach nazywa si ró nie:
znaczy to, e od teraz po wykonaniu kompilacji i utworzeniu TC.EXE, BC.EXE, BCW.EXE (dla Windows), itp.. Sprawd swoj
pliku wykonywalnego typu *.EXE, plik taki zostanie zapisany we wersj kompilatora i wpisz wła ciwe nazwy dodaj c ewentualnie
wskazanym katalogu i na wskazanym dysku/dyskietce. cie ki dost pu - np.:
[!!!]UWAGA Mo emy teraz wyj z programu C++. Rozwi menu File naciskaj c
________________________________________________________________ klawisze [Alt]-[F] i wybierz z menu rozkaz Quit. Pojawi si
Rozkazy uruchamiaj ce kompilator mog by zło one nawet z 4 okienko z ostrze eniem:
parametrów - np.:
WARNING: A:\PIERWSZY.CPP not saved. Save?
WIN /3 C:\BORLANDC\BIN\BCW C:\C-BELFER\PROGRAMY\P027.CPP (UWAGA: plik A:\PIERWSZY.CPP nie zapisany na dysku. Zapisa ?).
spowoduje: W ten sposób C++ ZNOWU chce Ci uchroni przed utrat programu,
* uruchomienie Windows w trybie rozszerzonym 386 ale uwa aj! Je li odpowiesz Tak ([Y] lub [Enter]), to nowa
* uruchomienie kompilatora w wersji dla Windows - BCW.EXE wersja programu zostanie nadpisana na star ! Je li odpowiesz Nie
* załadowanie pliku z programem - P27.CPP z wskazanego katalogu
________________________________________________________________ [N]
Dokonaj w swoim programie nast puj cych zmian: Po wyj ciu z C++ znajdziesz si w jego katalogu roboczym, lub w
________________________________________________________________ tym katalogu bie cym, z którego wydałe rozkaz uruchomienia
#include (stdio.h> kompilatora C++. Aby uruchomi swój program musisz zatem wyda
#include <conio> nast puj cy rozkaz:
main() A:\PIERWSZY.EXE
{ lub krócej
printf("\n"); A:\PIERWSZY
printf("Autor: np. Antoni Kowalski\n");
printf("program: PIERWSZY.CPP \n - wersja II \n"); a je li chcesz si przekona , czy Twój program jest tam, gdzie
getch(); powinien by , mo esz go zobaczy . Napisz rozkaz
}
________________________________________________________________ DIR A:\
lub
******Uwaga: Je li pracujesz w Windows - Z TEGO MIEJSCA******** DIR A:\*.EXE
przy pomocy rozkazów Edit | Copy Aby upewni si całkowicie, e to wła nie ten program, zwró
mo esz przenie program do okna kompilatora uwag na dat i czas utworzenia pliku. Je li masz prawidłowo
poprzez schowek Windows (Clipboard). ustawiony zegar w swoim komputerze, data powinna by dzisiejsza
W oknie kompilatora nale y: a czas - kilka minut temu. Je li co jest nie tak, powiniene
1. Otworzy nowe okno edytora tekstowego: przy pomocy rozkazów systemu DOS: DATE i TIME zrobi porz dek w
File | New swoim systemie. O takich drobiazgach warto pami ta . Pozwoli Ci
2. Wstawi plik ze schowka: to w przyszło ci odró ni nowsze i starsze wersje programów,
Edit | Paste unikn pomyłek i zaoszcz dzi wiele pracy.
--- To okno (AM-Edit) i całego BELFRA mo esz w tym czasie zredukowa
--- Do ikonki.------------------------------------------------------ [Z] 1. - Propozycja zadania - wiczenia do samodzielnego wykonania.
**************************************************************** -------------------------------------------------------------------
****
Spróbuj odszuka plik ródłowy .CPP i plik wynikowy .EXE
Dzi ki dodaniu do tekstu programu funkcji getch(), program nie wychodz c "na chwil " z IDE przy pomocy rozkazu File | DOS
powinien ju tak szybko mign na ekranie i znikn . Zatrzyma Shell.
si teraz i zaczeka na przyci ni cie klawisza. Funkcja getch(), -------------------------------------------------------------------
działa podobnie do:
A teraz zajrzyjmy do rodka do pliku PIERWSZY.EXE. Je li
10 IF INKEY$="" GOTO 10 korzystasz z programu Norton Commander, to masz do dyspozycji
opcje [F3] - View (przegl danie) i [F4] - Edit (edycja). Je li
w Basicu lub Readln w Pascalu. nie korzystasz z NC, musisz wyda nast puj cy rozkaz:
Nazwa pochodzi od GET CHaracter (POBIERZ ZNak, z klawiatury). TYPE A:\PIERWSZY.EXE | C:\DOS\MORE
lub
Skompiluj program PIERWSZY.CPP. Aby to zrobi , powiniene : C:\DOS\EDIT A:\PIERWSZY.EXE
1. Rozwin menu Compile - [Alt]-[C]. Jak widzisz na ekranie, napisy zawarte w programie pozostały
2. Wybra z menu rozkaz Compile - [C]. czytelne, ale to co wida dookoła nie wygl da najlepiej. Na
podstawie tego co widzisz, mo na (na razie ostro nie) wysnu
Ostrze enie WARNING na razie ignorujemy. wniosek, e ani Viewer (przegl darka), ani Edytor, które
doskonale spisuj si przy obróbce plików tekstowych, nie nadaj
Wykonaj kompilacj programu powtórnie przy pomocy rozkazu Run z si do analizy i obróbki programów w wersji *.EXE. Narz dziami,
menu Run. Naci nij kolejno klawisze: które b dziemy musieli stosowa , mog by programy typu
DEBUGGER, PROFILER, LINKER (konsolidator), kompilator i in..
[Alt]-[R], [R]
lub Mam nadziej , e czujesz si w rodowisku IDE ju troch
[Alt]-[R], [Enter] swobodniej, a wi c bierzemy si za drugi program.
__________________________________________________________
Ten sam efekt uzyskasz naciskaj c kombinacj klawiszy EOF
[Ctrl]-[F9].
Uruchom program powtórnie naciskaj c kombinacj klawiszy LEKCJA 5 - DZIAŁANIA PRZY POMOCY MYSZKI I BŁ DY W
[Alt]-[R], [R]. Zwró uwag , e teraz kompilacja nast pi PROGRAMIE.
znacznie szybciej. Tak naprawd C++ stwierdzi tylko, e od ________________________________________________________________
ostatniej kompilacji nie dokonano adnych zmian w programie i Z tej lekcji dowiesz si ,
odst pi od zb dnej kompilacji. Takie wła nie znaczenie ma * Jak posługiwa si myszk w rodowisku IDE (DOS)
komunikat "Checking dependences" (sprawdzam zale no ci, który * O czy nale y pami ta , przy tworzeniu i uruchamianiu
mignie w okienku kompilacji. Po korekcie programu napisy programów.
wygl daj znacznie przyzwoiciej, prawda? Po obejrzeniu napisów * Jak poprawia bł dy w programie.
11
________________________________________________________________ void main(void)
12
Aby przeanalizowa , jak kompilator C++ reaguje na bł dy w Twojego programu, lecz s zawarte w jednym z "fabrycznych"
programach, zmie tekst w pierwszej linii programu na bł dny: plików bibliotecznych zainstalowanych wraz z kompilatorem C++.
vod main(void)
{ [S]
} Function - Funkcja
Fuction call - Wywołanie funkcji
Spróbuj powtórnie skompilowa i uruchomi program. ________________________________________________________________
Kompilator wy wietli okienko, w którym pojawi si komunikat o Funkcja to co przypominaj ce mini-program. Funkcja zawiera
bł dach. W taki wła nie sposób kompilator taktownie informuje list rozkazów słu cych do wykonania typowych operacji (np.
programist , e nie jest a taki dobry, jak mu si czasami czyszczenie ekranu, wy wietlanie menu, wydruk, czy sortowanie
wydaje. Komputer jest niestety pedantem. Oczekuje (my, ludzie listy imion). W programach posługujemy si zwykle wieloma
tego nie wymagamy) absolutnej dokładno ci i elaznego funkcjami. Poznałe ju najwa niejsz funkcj główn - main(). W
przestrzegania pewnych zasad. "Zjadaj c" jedn liter naruszyłe C/C++ mo esz posługiwa si gotowymi funkcjami (tzw.
takie zasady, co zauwa ył kompilator. bibliotecznymi) a tak e tworzy nowe własne funkcje. Na razie
b dziemy posługiwa si gotowymi funkcjami dostarczanymi przez
W górnej cz ci ekranu kompilator wyró nił paskiem pod wietlenia producenta wraz z kompilatorem C++.
ten wiersz programu, który zawiera bł d. W dolnej cz ci ekranu, ________________________________________________________________
w tzw. okienku komunikatów (ang. Message window) pojawił si
komunikat, jaki rodzaj bł du został wykryty w Twoim programie. W
Wł cz kompilacj i prób uruchomienia programu.
danym przypadku komunikat brzmi: Kompilator stwierdzi, e program zawiera bł dy.
Naci nij dowolny klawisz, by znikn ło okienko kompilacji.
Declaration syntax error - Bł d w składni deklaracji Kompilator napisał:
Pierwsza linia (wiersz) funkcji nazywa si deklaracj funkcji. (Funkcja 'clrscr' powinna mie prototyp)
Taka pierwsza linia zawiera informacje wa ne dla kompilatora:
nazw funkcji oraz tzw. typy warto ci u ywanych przez funkcj . [???] O co mu chodzi?
Komunikat o bł dzie oznacza, e nieprawidłowo została napisana ________________________________________________________________
nazwa funkcji lub nazwy typów warto ci, którymi posługuje si Tzw. PROTOTYP funkcji to co bardzo podobnego do deklaracji
funkcja. W naszym przypadku słowo void zostało przekr cone na funkcji. Prototyp słu y do przekazania kompilatorowi pewnych
"vod", a słowo to ma w C++ specjalne znaczenie. Słowo "void" informacji o funkcji jeszcze przed u yciem tej funkcji w
jest cz ci j zyka C++, a dokładniej - słowem kluczowym (ang. programie. Dla przykładu, gdy pisałe pierwsz lini programu:
keyword).
void main(void)
[S] Function declaration - Deklaracja funkcji.
Keyword - Słowo kluczowe. podałe nie tylko nazw funkcji - main, lecz tak e umie cili my
________________________________________________________________ tam dwukrotnie słowo void. Dokładnie o znaczeniu tych słów
napiszemy w dalszej cz ci ksi ki. Na razie zwró my jedynie
Function declaration - Deklaracja funkcji. uwag , e podobnych "dodatkowych" informacji dotycz cych funkcji
Pierwszy wiersz funkcji jest nazywany deklaracj funkcji. Ten clrscr() w naszym programie nie ma.
wiersz zawiera informacje dla kompilatora C++ pozwalaj ce ________________________________________________________________
poprawnie przetłumaczy funkcj na kod maszynowy.
(ang. include - wł cz, doł cz) powoduje wł czenie we wskazane # include <conio.h> /* zwró uwag , e tu NIE MA [;] ! */
miejsce zawarto ci zewn trznego tekstowego pliku dyskowego - np.: # include <stdio.h> /* drugi plik nagłówkowy */
Aby przyst pi po wyja nieniach do pracy nad drugim programem, * int - od Integer - całkowity.
powiniene wykona nast puj ce czynno ci: Słowo kluczowe słu ce do deklaracji typu zmiennej lub funkcji.
Oznacza liczb całkowit np.: 768.
1. Zrób porz dek na ekranie. Zamknij rozkazem Close z menu
Window zb dne okna (mo esz posłu y si kombinacj [Alt]-[F3]). * #include - Wł cz.
2. Rozwi menu File. Dyrektywa wł czaj ca cały zewn trzny plik tekstowy. W tym
3. Wybierz z menu rozkaz Open... przypadku wł czone zostały dwa tzw. pliki nagłówkowe:
4. Wpisz do okienka tekstowego: CONIO.H i STDIO.H.
A:\DRUGI.CPP
5. Naci nij [Enter]. * CONIO.H - CONsole Input/Output.
14
Plik nagłówkowy zawieraj cy prototypy funkcji potrzebnych do main()
obsługi standardowego Wej cia/Wyj cia na/z konsoli (CONsole). {
Plik zawiera mi dzy innymi prototyp funkcji clrscr(), potrzebnej int i;
nam do czyszczenia ekranu.
printf("Dziesi liczb pseudo-losowych od 0 do 99\n\n");
*STDIO.H - STanDard Input/Output for(i=0; i<10; i++)
Plik nagłówkowy zawieraj cy prototypy funkcji potrzebnych do printf("%d\n", rand() % 100);
obsługi standardowego Wej cia/Wyj cia na/z konsoli (Input - return 0;
Wej cie, Output - Wyj cie). Plik zawiera mi dzy innymi prototyp }
funkcji printf(), potrzebnej nam do drukowania wyników na
ekranie. Przykad3
--------------------
return - słowo kluczowe: Powrót, zwrot. #include <stdlib.h>
#include <stdio.h>
Po wykonaniu programu liczba 0 (tak kazali my programowi #include <time.h>
rozkazem return 0;) jest zwracana do systemu operacyjnego, w
naszym przypadku do DOSa. Zwró uwag , e nie pojawiło si tym void main()
razem ostrze enie WARNING podczas kompilacji. {
________________________________________________________________ randomize();
printf("Liczby pseudolosowe z zakresu: 0-99 --> %d\n", random (100));
}
OPERATORY ARYTMETYCZNE C++.
Przykład 4
C++ potrafi oczywi cie nie tylko dzieli i mno y . Oto tabela -----------------
operatorów arytmetycznych c i C++. #include <stdlib.h>
#include <stdio.h>
OPERATORY ARYTMETYCZNE j zyka C++. #include <time.h>
________________________________________________________________
int main(void)
Operator Nazwa Tłumaczenie Działanie {
________________________________________________________________ int i;
5+7 12 [Z]
12 - 7 5 ________________________________________________________________
3*8 24 1. Zamie operator dzielenia na operator mno enia [*]:
10 / 3 3.333333
10 % 3 1 wynik = x * y; /* tu wykonuje sie mno enie */
________________________________________________________________
i napis w pierwszej funkcji printf() na np. taki:
1. Włó do nap du A: dyskietk z plikami PASCAL.H i POLTEKST.H. hokus-pokus. Skorzystali my z pewnej nie wyst puj cej ani w
2. Uruchom kompilator C++. Pascalu, ani w Basicu umiej tno ci j zyków C i C++ - a
mianowicie z PREPROCESORA.
PROGRAMY HOKUS.EXE i POKUS.EXE - czyli sztuczki z Preprpcesorem
C++ Najcz ciej stosowanymi dyrektywami preprocesora s :
[P004.CPP] #include
# include
#include <a:\pascal.h>
s całkowicie równowa ne. Poza tym dyrektywy preprocesora nie
Program ko cz si rednikiem.
Begin
Write("Ten program jest podobny"); Działanie preprocesora (czyli wst pne przetwarzanie tekstu
Write(" do Turbo Pascala "); programu jeszcze przed przyst pieniem do kompilacji) polega na
Write(" tak tez mozna pisac w BORLAND C++ !"); zast pieniu w tek cie programu jednych ła cuchów znaków przez
Readln; inne. Takie pary mo emy "zada " preprocesorowi wła nie dyrektyw
End
#define. Nasze nagłówki wygl daj nast puj co:
[P005.CPP] "printf"
16
- ten, KTÓRY NALE Y PODSTAWIA . Cz sto w programach - a poszczególne pliki - modułami lub elementami składowymi
zauwa ysz ła cuchy znaków pisane w do specjalny sposób: projektu:
[???] Dla dociekliwych - kilka słów o funkcji main() podajemy równie tzw. ciało funkcji, np.:
________________________________________________________________
Funkcja main() wyst puje najcz ciej w nast puj cych {
(równowa nych) postaciach: printf("wydrukuj cokolwiek");
return 0;
main() int main() int main(void) }
- program w momencie uruchomienia nie pobiera adnych argumentów jest to jednocze nie DEFINICJA FUNKCJI main().
Zwró uwag , e funkcja printf() nie jest w powy szym
z wiersza rozkazu --> () lub (void) przykładzie w aden sposób ani deklarowana ani definiowana.
- program zwraca po zako czeniu jedn liczn (int = integer - Wiersz:
liczba całkowita) do systemu operacyjnego informuj c go w taki
sposób, czy wykonał si do ko ca i bezbł dnie i czy mo na go printf("pisz!");
usun z pami ci (bywaj tak e programy rezyduj ce w pami ci -
tzw. TSR, o czym system operacyjny powinien "wiedzie "). stanowi WYWOŁANIE funkcji printf() z parametrem 'pisz!' -
ła cuchem znaków, który nale y wydrukowa .
void main() void main(void) W C++ nawet je li nawiasy przeznaczone w funkcji na przekazanie
jej argumentów s puste - musz by obecne. Poprawne wywołanie
- program nie pobiera i nie zwraca adnych paramatrów. funkcji w j zyku C++ mo e mie nast puj c form :
Główna funkcja main() mo e w rodowisku okienkowym przeobrazi
si w główn funkcj okienkow : nazwa_funkcji();
Poniewa nasz kurs j zyka C++ rozpocz li my od programu z których np. przy u yciu dyrektywy #define zostały PREDEFINIOWANE
funkcj printf() i zapewne b dzie nam ona towarzyszy jeszcze
długo, pora po wi ci jej troch uwagi. (zdefiniowane wst pnie) niektóre stałe. Je li jeste bardzo
dociekliwy, zajrzyj do wn trza pliku STDIO.H (view, edit, type).
FUNKCJA printf().
Znajdziesz tam mi dzy innymi taki wiersz:
Jest to funkcja FORMATOWANEGO wyj cia na standardowe urz dzenie
wyj cia (ang. stdout - STandarD OUTput). Definicja - ci lej #define EOF (-1) //End of file indicator
tzw. PROTOTYP tej funkcji znajduje si w pliku nagłówkowym ________________________________________________________________
STDIO.H. Wniosek praktyczny: Ka dy program korzystaj cy z
funkcji printf() powinien zawiera dyrektyw preprocesora: Składnia prototypu (ang. syntax):
C++ jest mniej tolerancyjny. Je li zapomnisz doł czy odpowiedni Poniewa FORMAT brzmi mo e troch obco, nazwijmy go WZORCEM. Jak
plik nagłówkowy mo e pojawi si komunikat: wiesz, wszystkie informacje przechowywane s w pami ci komputera
Error: Function printf() should have a prototype in function jako ci gi zer i jedynek. Jest to forma troch niewygodna dla
main człowieka, wi c zanim informacja trafi na ekran musi zosta
(Funkcja printf() powinna mie prototyp) zamieniona na posta dla nas wygodniejsz - np. na cyfry
dziesi tne, litery itp.. Taki proces nazywany jest KONWERSJ , a
Wi cej o zawarto ci i znaczeniu plików nagłówkowych *.h dowiesz podany w funkcji printf() FORMAT - WZORZEC to upraszczaj c,
si z nast pnych lekcji. Na razie postaraj si pomi ta o rozkaz dokonania takiej wła nie konwersii. Mo esz wi c zarz da
doł czeniu wskazanego w przykładzie pliku. przedstawienia liczby na ekranie w postaci np. SZESNASTKOWEJ lub
________________________________________________________________
DZIESI TNEJ - tak, jak Ci wygodniej. Wzorce konwersji w
[???] Sk d to wiadomo? najprostszym przypadku maj posta %s, %d, %f, itp.:
________________________________________________________________ I tak:
Je li masz w tpliwo ci, jaki plik nagłówkowy nale ałoby doł czy
%s - wyprowad ła cuch znaków (s - String - ła cuch)
- najpro ciej zajrze do systemu pomocy - Help. Na pasku Przykład:
głównego menu w IDE masz napis Help. Menu Help mo esz rozwin
myszk lub naciskaj c kombinacj klawiszy [Alt]+[H]. Je li w printf("%s","jakis napis");
menu wybierzesz rozkaz Index (Spis) przeniesiesz si do okienka ale tak e
z alfabetycznym spisem haseł. S tam słowa kluczowe, nazwy printf("Jakis napis");
funkcji i jeszcze wiele innych interesuj cych rzeczy. Powiniene
poniewa format "%s" jest formatem domy lnym dla funkcji
18
printf(). }
formatu: Przykład:
%[przeł czniki][szeroko _pola][.precyzja][rozmiar]Typ printf("Iloczyn 3 %c 5 %9s %f", 'x', "wynosi ", 3*5);
Posługuj c si ró nymi sposobami formatowania liczb mo emy Zwró uwag , e tym razem kazali my komputerowi samodzielnie
za da wydrukowania liczb w najwygodniejszej dla nas formie. W policzy ile wynosi nasz iloczyn, tzn. zastosowali my jako
programie przykładowym dokonujemy zamiany liczb dziesi tnych na argument funkcji printf() nie stał , a WYRA ENIE. Działanie
szesnastkowe. mo esz prze ledzi przy pomocy programu przykładowego:
[P006.CPP] [P008.CPP]
Oto pełna lista słów kluczowych Turbo C++ v 1.0 z krótkim protected - chroniona, cz danych i funkcji, do których
wyja nieniem ich znaczenia. Zaczynam od listy podstawowej wersji dost p. jest ograniczony.
kompilatora, poniewa rozwa ania o niuansach dotycz cych kilku
specyficznych słów kluczowych (np. friend, template) pozostawiam public - publiczna, dost pna z zewn trz.
sobie na pó niej. Krótkie wyja nienie - jak to krótkie
wyja nienie - pewnie nie wyja ni wszystkiego od razu, ale na register - zmienn przechwaj nie w pami ci a w rejestrze CPU.
pewno pomo e zrozumie znaczenie wi kszo ci słów kluczowych.
return - powrót, zwrot warto ci.
[S] Keywords - słowa kluczowe.
_saveregs - save registers, zachowaj zawarto rejestrów a
asm nast pnie odtwórz rejestry przed powrotem.
Pozwala wstawi kod w ASEMBLERZE bezpo rednio do programu
napisanego w C lub C++. _seg - segment.
auto - zmienna lokalna. Przyjmowane domy lnie. short - krótka (mała ilo cyfr).
_export - dotyczy tylko OS/2, ignorowany. Panuje mnienanie, e j zyk C++ posługuje si stosunkowo skromnym
zestawem słów kluczowych. To prawda, ale nie cała prawda o
extern - zewn trzna. j zyku C++. Zauwa yłe zapewne, e nie ma tu:
far - dalekie. Wska nik - podwójne słowo (w zakresie do 1 MB). define, include, printf
float - zmiennoprzecinkowy, rzeczywisty. i innych znanych Ci ju słów. To po prostu jeszcze nie cały
słownik j zyka. Zdaj c sobie spraw z nieprecyzyjno ci tego
for - dla (wskazanie zmiennej roboczej w p tli). porównania mo esz przyj , e to co na kształt listy
czasowników. A s przecie jeszcze i inne słowa - o innej roli i
friend - zaprzyja niona funkcja z dost pem do prywatnych i przeznaczeniu.
chronionych członków danej klasy.
[???] A GDZIE SI PODZIAŁY REJESTRY ???
goto - skocz do (skok bezwarunkowy).
Nazwy rejestrów mikroprocesora Intel 80X86:
huge - daleki, podobnie do far.
_AX _AL _AH _SI _CS
if - je eli (pod warunkiem, e...). _BX _BL _BH _SP _DS
_CX _CL _CH _BP _ES
inline - funkcja z rozwini tym wstawionym kodem _DX _DL _DH _DI _SS
_FLAGS
int - typ zmiennej, liczba całkowita, dwa bajty
Takie oznaczenia wynikaj z architektury konkretnej rodziny
interrupt - przerwanie. mikroprocesorów, nie mog stanowi uniwersalnego standardu
j zyka C++. Efekt dostosowania C++ do IBM PC to np. odnosz ce
_loadds - podobne do huge, ustawia rejestr DS (Data Segment). si do modeli pami ci słowa kluczowe near, far i huge.
Wymóg zgodno ci ze standardem ANSI C spowodował, e w C++ nazwy
long - długi. rejestrów pozostaj nazwami o zastrze onym znaczeniu, ale
nazywaj si PSEUDOZMIENNYMI REJESTROWYMI (ang.: Register
near - bliski, wska nik o dł. 1 słowa. Obszar max. 64 K. Pseudovariables).
new - nowy, utwórz nowy obiekt. Próba u ycia słowa o zastrze onym znaczeniu w jakiejkolwiek
innej roli (np. jako nazwa Twojej zmiennej) mo e spowodowa
operator - operator, okre la nowy sposób działania operatora. wadliwe działanie programu lub uniemo liwi kompilacj . Unikaj
przypadkowego zastosowania słów o zastrze onym znaczeniu!
pascal - deklar. funkcji zgodnej ze standardem przekazywania
parametrów przyj tym w Pascalu. [???] A SK D MAM WIEDZIEC ?
21
List nazw, które maj ju nadane ci le okre lone znaczenie w Ła cuch znaków to taki ci g znaków, który komputer mo e
C++ znajdziesz w Help. Dost p do spisu uzyskasz przez: rozpatrywa wył cznie jako cało i posługiwa si nim tylko
tak, jak go wpisałe . Aby komputer poprawnie rozpoznawał
* Rozwini cie menu Help [Alt]-[H]; ła cuchy tekstowe - nale y ujmowa je w cudzysłów. Ła cuch
* Wybranie z menu Help rozkazu Index (spis). znaków mo e by nazywany równie literałem, b d literałem
ła cuchowym.
Wróci do edytora IDE C++ mo esz przez [Esc].
[!!!] Dla dociekliwych - jak C++ zapami tuje tekst?
SŁOWA TYPOWE DLA PROGRAMÓW OBIEKTOWYCH.
Pojedyncze znaki mo na zapisywa w C++ tak:
W porównaniu z klasycznym j zykiem C (wobec którego C++ jest
nadzbiorem - ang. superset), w nowoczesnych programach 'A' - pojedynczy znak reprezentowany w pami ci komutera jako
obiektowych i zdarzeniowych pisanych w C++ mog pojawia si i jeden bajt zawieraj cy liczb - numer litery A według kodu
inne słowa. Przyjrzyjmy si na troch inn technik ASCII. W tym przypadku byłaby to liczba 65 (dwójkowo i
programowania - bardziej charakterystyczn dla C++. szesnastkowo- odpowiednio: 0100 0001 i 41).
"A" - jednoelementowy ła cuch znaków zajmuj cy w pami ci dwa
Procesy wprowadzania i wyprowadzania danych do- i z- komputera bajty (kod litery A i znak ko ca ła cucha - \0). Reprezentacja w
nazywaj si Input i Output - w skrócie I/O (lub bardziej
swojsko We/Wy). Obsługa We/Wy komputera to sała obszerna wiedza, pami ci wygl dałaby tak:
na pocz tek b dzie nam jednak potrzebne tylko kilka najbardziej
istotnych informacji. Bajt Nr X 0100 0001 - kod ASCII litery A
Bajt Nr X+1 0000 0000 - kod ASCII 0 - znak ko ca
PROBLEM ˙WEJ CIA/WYJ CIA W PROGRAMACH - troch bardziej
ogólnie.
Wiesz ju , e clrscr(); stanowi wywołanie gotowej funkcji (tzw.
Operacje wej cia i wyj cia s zwykle kontrolowane przez funkcji bibliotecznej). Informacja dotycz ca tej funkcji (tzw.
pracuj cy wła nie program. Je li uruchomiłe program, który nie prototyp funkcji) znajduje si w pliku CONIO.H, dlatego
korzysta z klawiatury i nie oczekuje na wprowadzenie przez doł czyli my ten plik nagłówkowy na pocz tku programu dyrektyw
u ytkownika adnych informacji - mo esz naciska dowolne #include. A có to za dziwol g ten "cout" ?
klawisze - program i tak ma to w nosie. Podobnie, je li w Po cout nie ma pary nawiasów okr głych (gdyby to była
programie nie przewidziano wykorzystania drukarki, cho by funkcja - powinno by cout()) - nie jest to zatem wywołanie
"wyłaził ze skóry", adne informacje nie zostan przesłane do funkcji. ˙Strumie danych wyj ciowych cout - JEST OBIEKTEM (ang.
drukarki, dla programu i dla u ytkownika drukarka pozostanie I/O stream object - obiekt: strumie Wej cia/Wyj cia). Ale nie
niedost pna. Aby programy mogły zapanowa nad Wej ciem i przestrasz si . Popularne wyobra enie, e programowanie
Wyj ciem informacji, wszystkie j zyki programowania musz obiektowe jest czym bardzo skomplikowanym nie ma z prawd
zawiera specjalne rozkazy przeznaczone do obsługi wi cej wspólnego, ni powszechny do pogl d, e baba z pustym
Wej cia/Wyj cia (ang. Input/Output commands, lub I/O wiadrem jest gorsza od czarnego kota. W gruncie rzeczy jest
instructions). Bez umiej tno ci obsługi We/Wy, czyli bez to proste. Strumie to nic innego jak zwyczajny przepływ
mo liwo ci porozumiewania si ze wiatem zewn trznym psu na bud informacji od jednego urz dzenia do innego. W tym przypadku
zdałby si ka dy j zyk programowania. Ka dy program musi w strumie (przepływ) danych oznacza przesłanie informacji
wi kszym, b d mniejszym stopniu pobiera informacje ze wiata (tekstu) z pami ci komputera na ekran monitora. Trójk tne
zewn trznego do komputera i wysyła informacje z komputera na nawiasy (<< lub >>) wskazuj kierunek przepływu informacji.
zewn trz. Przesyłanie nast puje w naszym przypadku z pami ci do strumienia
Podobnie, jak wszystkie uniwersalne j zyki programowania - j zyk Pojawiło si tu wa ne słowo - OBIEKT. Obiekt podobnie jak
C++ zawiera pewn ilo rozkazów przeznaczonych do zarz dzania program komputerowy jest to grupa danych i funkcji działaj cych
obsług wej cia i wyj cia. Dla przykładu, mo emy w j zyku C++ wspólnie i przeznaczonych razem do wykonania jakich zada . Dla
zastosowa OBIEKT cout obsługuj cy strumie danych wyj ciowych. przykładu obiekt cout słu y do obsługi przesyłania danych na
Obiekt cout (skonstruowany przez producenta i zdefiniowany w ekran monitora. Słowo "obiekt" jest cz sto u ywane w opisach
pliku nagłówkowym IOSTREAM.H) pozwala programi cie nowoczesnych technik programowania - tzw. PROGRAMOWANIA
przesła dane tekstowe i/lub numeryczne do strumienia wyj ciwego OBIEKTOWEGO. Programowanie obiektowe, ta "wy sza szkoła jazdy"
i umie ci tekst na ekranie monitora. dla programistów z lat 80-tych jest ju wła ciwie w naszych
czasach norm . Zreszt widzisz sam - napisałe program obiektowy
Wczytaj plik ródłowy z programem COUT1.CPP lub wpisz i co - i nic strasznego si nie stało. Na pocz tek musisz
samodzielnie nast puj cy program przykładowy. Program drukuje wiedzie tylko tyle, e aby posługiwa si obiektami -
tekst na ekranie monitora. strumieniami wej cie i wyj cia - nale y doł czy w C++ plik
nagłówkowy IOSTREAM.H. Dlatego dyrektywa #include <iostream.h>
[P009.CPP] znajduje si na pocz tku przykładowego programu.
#include <iostream.h> <-- zwró uwag na inny, nowy plik KILKA ARGUMENTÓW FUNKCJI w praktyce.
#include <conio.h>
Jak starałem si wykaza w przykładzie z sinusem, funkcja mo e
void main(void) otrzymac jako argument stał - np. okre lon liczb , b d
{ zmienn (niewiadom ). Niektóre funkcje mog otrzymywa w
clrscr(); momencie ich wywołania (u ycia w programie) wi cej ni jeden
cout << "Stosujemy obiekt cout:\n"; argument. Rozwa my to dokładniej na przykładzie funkcji
cout << "Tekst pierwszy\n"; fprintf() zbli onej w działaniu do printf(), lecz bardziej
cout << "Tekst drugi...\n"; uniwersalnej. Funkcja fprintf() pozwala wyprowadza dane nie
getch(); tylko na monitor, ale tak e na drukark . Skoro urz dzenia
} wyj cia mog by ró ne, trzeba funkcji przekaza jako jeden z
jej argumentów informacj o tym - na które urz dzenie yczymy
Jak widzisz, ka dy rozkaz z u yciem obiektu cout tworzy sobie w danej chwili wyprowadza dane.
pojedyncz lini tekstu (wiersz) na ekranie monitora. Kompilator
j zyka C++ wie, e chcesz wysła tekst na ekran monitora dzi ki Słowo stdout jest pierwsz informacj (tzw. parametrem, b d
słowu cout i znakowi << (znak << to tzw. operator przesyłania do argumentem funkcji) przekazanym do funkcji fprintf(). Słowo
strumienia). Wysłany na ekran zostaje tekst umieszczony po stdout jest skrótem od Standard Output - standardowe wyj cie.
operatorze << i (obowi zkowo, podobnie jak w funkcji printf()) Oznacza to w skrócie typowe urz dzenie wyj ciowe podł czone do
uj ty w cudzysłów ("). Tekst uj ty w cudzysłów nazywa si komputera ˙i umo liwiaj ce wyprowadzenie informacji z komputera.
ła cuchem znakowym (ang. string literal).
W komputerach osobistych zgodnych ze standardem IBM PC tym
[S] String literal - ła cuch znaków. typowym urz dzeniem wyj ciowym jest prawie zawsze ekran
monitora.
Ła cuch znaków to grupa znaków alfanumerycznych (tekstowych).
22
Tekst, który ma zosta wydrukowany na ekranie monitora jest Ilo tych komórek w Twoim komputerze zale y od tego ile pami ci
drug informacj przekazywan do funkcji fprintf() - inaczej -
stanowi drugi parametr funkcji. Tekst - ła cuch znaków - musi zainstalujesz (np. 4MB RAM to 4x1024x124x8 bitów - chcesz -
zosta uj ty w znaki cudzysłowu. policz sam ile to bitów). Przeliczaj c zwró uwag , e kilobajt
(KB to nie 1000 - lecz 1024 bajty a megabajt - 1024 kB).
A je li zechcesz wyprowadzi tekst na drukark ?
W C++ zapisuje si to bardzo łatwo. Wystarczy słowo stdout Zastanówmy si , sk d program mo e wiedzie gdzie, w której
(oznaczaj ce monitor) zamieni na słowo stdprn. Słowo stdprn to komórce zostały umieszczone dane i jak si do nich dobra , gdy
skrót od Standard Printer Device - standardowa drukarka. Oto stan si potrzebne. Wła nie do takich celów potrzebne s
przykład praktycznego u ycia funkcji fprintf(). Program przesyła programowi ZMIENNE (ang. variables).
tekst na drukark . Przed uruchomieniem programu pami taj o
wł czeniu drukarki. Dawno, dawno temu rozwi zywałe zapewne zadania typu:
[P010.CPP] 3+[]=5
W uproszczeniu mo esz wyobrazi sobie pami komputera jako oznacza ˙w C++ : pobierz dane ze strumienia wej ciowego i umie
miliony pojedynczych komórek, a w ka dej z komórek jaka jedna w zmiennej o nazwie "nazwa_zmiennej".Te informacje, które
warto (ang. value) zakodowana w postaci ZER i JEDYNEK. Ka da zostan ˙wczytane, C++ przechowuje w przgródce oznaczonej nazw ,
taka "szara" komórka ma numer-adres. Numeracja komórek któr nadajesz zmiennej. Oto program przykładowy ilustruj cy
rozpoczyna si nie od 1 lecz od zera (pierwsza ma numer 0). zapami tywanie danych wprowadzonych przez u ytkownika z
23
klawiatury, wczytanych do programu przy pomocy obiektu cin i zastosowa nawet w rodku wiersza tekstu - sprawd ).
zapami tanych w zadeklarowanej wcze niej zmiennej x: Zwró uwag w jaki sposób C++ rozpoznaje ró nic pomi dzy:
void main(void) Wida tu wyra nie, dlaczego znak cudzysłowu jest dla kompilatora
{ istotny. Je li pominiemy cudzysłów, C++ b dzie próbował
int x; zinterpretowa liter (tekst) jako nazw zmiennej a nie jako
cout << "Podaj liczbe calkowita 0 - 1000 do zapamietania: "; napis.
cin >> x;
cout << "Pamietam! "; RODZAJE ZMIENNYCH: ZMIENNE NUMERYCZNE I ZMIENNE
cout << "Wielokrotnosci liczby: \n": TEKSTOWE.
cout << "x, 2x, 3x: " << x << " " << 2*x << " " << 3*x;
cout << "\n ...Nacisnij dowolny klawisz..."; Zmienne mog w C++ by bardzo elastyczne. Dokładnie rzecz
getch(); bior c, zmienne mog by :
}
RÓ NYCH TYPÓW - mog by liczbami, mog tak e by tekstami.
Zapis cin >> x oznacza: "pobierz dane ze strumienia danych Uruchom program jeszcze raz i zamiast liczby naci nij w
wej ciowych i umie je w pami ci przeznaczonej dla zmiennej x". odpowiedzi na pytanie klawisz z liter . Program wydrukuje jakie
bzdury. Dzieje si tak dlatago, e program oczekuje podania
x - to nazwa (identyfikator) zmiennej. Ta nazwa jest stosowana liczby i zakłada, e wprowadzone przez u ytkownika dane s
przez komputer do identyfikacji przegródki w pami ci, w której liczb .
b dzie przechowywana liczba wpisana przez u ytkownika jako
odpowied na zadane pytanie. Kompilator C++ zarezerwuje dla [???] A je li u ytkownik nie czyta uwa nie???
zmiennej x jak komórk pami ci i umie ci tam wpisan przez
Ciebie liczb . W trakcie pracy kompilator C++ tworzy dla C++ zakłada, e u ytkownik wie co robi gdy podaje warto
własnego u ytku tzw. tablic symboli, któr posługuje si do zmiennej. Je li wprowadzone zostan dane niewła ciwego typu -
rozmieszczania danych w pami ci. Je li chcesz, mo esz sprawdzi C++ nie przerywa działania programu i nie ostrzega przed
przy pomocy Debuggera (Debug | Inspect) w których bajtach RAM niebezpiecze stwem bł du. Sam dokonuje tzw. konwersji typów -
C++ umie cił Twoj zmienn . tzn. przekształca dane na warto typu zgodnego z zadeklarowanym
w programie typem zmiennej. To programista musi dopilnowa , by
[???] Ile miejsca trzeba zarezerwowa ? pobrane od u ytkownika dane okazały si warto ci odpowiedniego,
oczekiwanego przez program typu, lub przewidzie w programie
To, ile miejsca trzeba zarezerwowa dla danej zmiennej sposób obsługi sytuacji bł dnych.
kompilator "wie" dzi ki Twojej deklaracji, jakiego typu dane
b d przechowywane w miejscu przeznaczonym dla zmiennej. Dla
przykładu: Mo na utworzy zmienn przeznaczon do przechowywania w pami ci
- je li napiszesz int x; tekstu - napisu. Aby to zrobi musimy zadeklarowa co
Kompilatoer zarezerwuje 2 bajty jako ciowo nowego tzw. TABLIC ZNAKOW (ang. character array).
- je li napiszesz float y; Jest to nazwa, przy pomocy której komputer lokalizuje w pami ci
Kompilatoer zarezerwuje 4 bajty zbiór znaków. Aby zadeklarowa zmienn (tablic ) znakow w C++
itp...(szczegóły - patrz ni ej). musimy zacz od słowa kluczowego char (ang. CHARacter - znak).
Nast pnie podajemy nazw zmiennej a po nazwie w nawiasach
Zwykle nie musisz si przejmowa tym, w którym miejscu kwadratowych ilo znaków, z których mo e składa si zmienny
kompilator rozmie cił Twoje dane. Wszystkie czynno ci C++ wykona tekst, który zamierzamy przechowywa w pami ci pod t nazw .
automatycznie. Aby jednak wszystko przebiegało poprawnie - zanim
zastosujesz jak kolwiek zmienn w swoim programie - musisz W programie poni ej zmienna x nie jest ju miejscem w pami ci
ZADEKLAROWA ZMIENN . Deklaracja zmiennej to informacja dla słu cym do przechowywania pojedynczej liczby. Tym razem nazwa
kompilatora, ile i jakich zmiennych b dziemy stosowa w (identyfikator zmiennej) x oznacza tablic znakow , w której
programie. Deklaracja zawiera nie tylko nazw zmiennej, ale mo na przechowywa tekst o długo ci do 20 znaków. W C++ ostatnim
równie typ warto ci, jakie ta zmienna mo e przybiera . znakiem w ła cuchu znakowym (tek cie) b d w tablicy znakowej
Przykładem deklaracji jest wiersz: zwykle jest tzw. NULL CHARACTER - niewidoczny znak o kodzie
ASCII 0 (zero). W C++ znak ten podaje si przy pomocy szyfru
int x; '\0'. Przy pomocy tego znaku C++ odnajduje koniec tekstu,
ła cucha znaków, b d koniec tablicy znakowej. Tak wi c w
Słowo kluczowe int okre la typ danych. Tu oznacza to, e zmienna tablicy x[20] w rzeczywisto ci mo na przechowa najwy ej 19
x mo e przechowywa jako warto ci liczby całkowite (ang. INTeger dowolnych znaków plus na ko cu obowi zkowy NULL (wartownik).
- całkowity) o wielko ci zawartej w przedziale - 32768...+32767.
Po okre leniu typu danych nast puje w deklaracji nazwa zmiennej [P012.CPP]
i rednik.
#include <conio.h>
[S] Variable Declaration - Dekaracja Zmiennej. #include <iostream.h>
Deklaracja zmiennej w C++ to okre lenie typu warto ci zmiennej i void main(void)
podanie nazwy zmiennej. {
char x[20]; //<---- deklaracja tablicy znakowej.
LEKCJA 9: O SPOSOBACH ODWOŁYWANIA SI DO DANYCH. Wbrew pierwszemu mylnemu wra eniu te dwie liczby stanowi jeden
________________________________________________________________ argument funkcji. C++ najpierw dokona dodawania 4+128 a dopiero
W trakcie tej lekcji poznasz: uzyskany wynik 132 przeka e funkcji textcolor jako jej argument
* sposoby wyprowadzania napisów w ró nych kolorach (parametr). Liczba 4 to kod koloru czerwonego, a zwi kszenie
* sposoby zapami tywania tekstów kodu koloru o 128 powoduje, e tekst b dzie migał.
* sposoby odwoływania si do danyc i zmiennych przy pomocy ich
nazw - identyfikatorów. Numery (kody) kolorów, które mo esz przekaza jako argumenty
________________________________________________________________ funkcji textcolor() podano w tabeli poni ej. Je li tekst ma
miga - nale y doda 128 do numeru odpowiedniego koloru.
Mo emy teraz po wi ci chwil na zagadnienie kolorów, które
pojawiaj si na monitorze. Po uruchomieniu program przykładowy Kod koloru przekazywany do funkcji textcolor().
poni ej wygeneruje krótki d wi k i zapyta o imi . Po wpisaniu ________________________________________________________________
imienia program zapiszczy jeszcze raz i zapyta o nazwisko. Po
wpisaniu nazwiska program zmieni kolor na ekranie monitora i Kod Kolor (ang) Kolor (pol) Stała
wypisze komunikat kolorowymi literami. Ró ne kolory zobaczysz n (przykład)
oczywi cie tylko wtedy, gdy masz kolorowy monitor. Dla ________________________________________________________________
popularnego zestawu VGA mono b d to ró ne odcienie szaro ci.
Tekst powinien zmienia kolor i "miga " (ang. - blinking text). 0 Black Czarny BLACK
1 Blue Niebieski BLUE
[P012.CPP] 2 Green Zielony GREEN
3 Cyan Morski CYAN
#include <conio.h> 4 Red Czerwony
#include <iostream.h> 5 Magenta Fioletowy
6 Brown Br zowy
main() 7 White Biały
{ 8 Gray Szary
char imie[20]; 9 Light blue Jasno niebieski
char nazwisko[20]; 10 Light green Jasno zielony
11 Light cyan Morski - jasny
clrscr(); 12 Light red Jasno czerwony
cout << "\aPodaj imie: "; 13 Light magenta Jasno fio;etowy (fiol-ró owy)
cin >> imie; 14 Yellow ółty
cout << "\aPodaj nazwisko: "; 15 Bright white Biały rozja niony
cin >> nazwisko; 128 + n Blinking Migaj cy BLINK
cout << '\n' << imie << ' ' << nazwisko << '\n'; ________________________________________________________________
textcolor(4+128);
cprintf("\nPan(i), %s %s? Bardzo mi milo!", imie, nazwisko);
getch(); [!!!]UWAGA:
cout << '\a'; ________________________________________________________________
return 0; * W pliku CONIO.H s predefiniowane stałe (skrajna prawa kolumna
}
- przykłady), które mo esz stosowa jako argumenty funkcji.
Wyja nijmy kilka szczegółów technicznych: Kolor tła mo esz ustawi np. przy pomocy funkcji
textbackground() - np. textbacground(RED);
cout << "\aPodaj nazwisko? ";
/* \a to kod pisku gło niczka (beep) */ * Manipuluj c kolorem tekstu musisz pami ta , e je li kolor
napisu:
cin >> nazwisko; - foreground color, text color
textcolor(4+128); <---- funkcja zmienia kolor tekstu i kolor tła:
- background color
cprintf("\nPan(i), %s %s? Bardzo mi milo!", imie, nazwisko); oka si identyczne - tekst zrobi si NIEWIDOCZNY. Je li ka esz
___ tu funkcja wstawi "string" nazwisko
| |________ a tu wstawi "string" imie komputerowi pisa czerwonymi literami na czerwonym tle -
|_________ funkcja wyprowadza tekst na ekran w kolorach komputer wykona rozkaz. Jednak e wi kszo ludzi ma kłopoty z
(cprintf = Color PRINTing Function) odczytywaniem czarnego tekstu na czarnym tle. Jest to jednak
metoda stosowana czasem w praktyce programowania do kasowania
tekstów i elementów graficznych na ekranie.
Operator >> pobiera ze strumienia danych wej ciowych cin wpisane ________________________________________________________________
Funkcja textcolor() pozwala na zmian koloru tekstu to słowa kluczowe - MUSZ ZAWSZE BY PISANE MAŁYMI LITERAMI)
wyprowadzanego na monitor. Mo na przy pomocy tej funkcji tak e mo na stosowa i małe i du e litery. Litery du e i małe s
"zmusi " tekst do migotania. Aby funkcja zadziałała - musimy rozró niane. Przykład:
25
* Dziesi tne (przyjmowane domy lnie - default);
[P013.CPP] * Ósemkowe - zapisywane z zerem na pocz tku:
017 = 1*8 + 7 = 15 (dziesi tnie);
#include <stdio.h> * Szesnastkowe - zapisywane z 0x na pocz tku:
#include <conio.h> 0x17 = 1*16 + 7 = 23 (dziesi tnie);
0x100 = 16^2 + 0 + 0 = 256 .
float PI = 3.14159; <-- stała PI
float r; <-- zmienna r Liczby rzeczywiste mog zawiera cz ułamkow lub by zapisane
[!!!]Jak sprawdzi kod ASCII znaku? Wykonaj od nowa kompilacj programu [F9].
________________________________________________________________
Mo na oczyw cie nauczy si tabeli kodów ASCII na pami (dla [???] ... is up to date...
pocz tkowych i najwa niejszych stronic kodowych - przede ________________________________________________________________
wszystkom od 0 do 852). Dla hobbystów - stronica kodowa 1250 i Je li C++ nie zechce powtórzy kompilacji i odpowie Ci:
1252 te czasem si przydaje.
(to oczywi cie art - autor nie zna ani jednego faceta o tak Making
genialnej pami ci) A:\GOTOTEST.CPP
Mo na skorzysta z edytora programu Norton Commander. W trybie
Edit [F4] po wskazaniu kursorem znaku w górnym wierszu po prawej is up to date
stronie zostanie wy wietlony jego kod ASCII. (Program w takiej wersji ju skompilowałem, wi cej nie b d !)
________________________________________________________________
nie przejmuj si . Dokonaj jakiejkolwiek pozornej zmiany w
CZY PROGRAM NIE MÓGŁBY CHODZI W KÓŁKO? programie (np. dodaj spacj lub pusty wiersz w dowolnym
miejscu). Takich pozornych zmian wystarczy by oszuka C++. C++
Twoja intuicja programisty z pewno ci podpowiada Ci, e gdyby nie jest na tyle inteligentny, by rozró nia zmiany rzeczywiste
zmusi komputer do pracy w p tli, to nie musiałby przykładowych w pliku ródłowym od pozornych.
________________________________________________________________
programów uruchamia wielokrotnie. Spróbujmy nakaza programowi
przykładowemu chodzi "w kółko". To proste - dodamy do programu:
Powtórz kompilacj programu. Nie musisz uruchamia programu.
Zwró uwag tym razem na pojawiaj ce si w okienku komunikatów
* na ko cu rozkaz skoku bezwarunkowego goto (id do...), ostrze enie:
* a eby wiedział dok d ma sobie i - na pocz tku programu
zaznaczymy miejsce przy pomocy umownego znaku - ETYKIETY. Warning: A:\GOTOTEST.CPP 14: Unreachable code in function main.
(Uwaga: Kod programu zawiera takie rozkazy, które nigdy nie
Zwró uwag , e pisz c pliki wsadowe typu *.BAT w j zyku BPL zostan wykonane inaczej - "s nieosi galne").
(Batch Programming Language - j zyk programowania wsadowego)
stawiasz dwukropek zawsze na pocz tku etykiety: O co chodzi? Przyjrzyj si tekstowi programu. Nawet je li po
rozkazie skoku bezwarunkowego:
:ETYKIETA (BPL)
goto etykieta;
a w j zyku C++ zawsze na ko cu etykiety:
dopiszesz jakikolwiek inny rozkaz, to program nigdy tego rozkazu
ETYKIETA: (C/C++)
nie wykona. Wła nie o to chodzi. Program nie mo e nawet nigdy
Przyst pujemy do opracowania programu. wykona rozkazu "return 0", który dodali my "z przyzwyczajenia".
* Je li wyst piły bł dy, popraw i powtórz prób kompilacji. [S] some important keywords - kilka wa nych słów kluczowych
* Uruchom program [Alt]-[R], [R] (lub [Ctrl]-[F9]). ________________________________________________________________
* Podaj kilka liczb: np. 1,2,5,7,8 itp. for - dla (znaczenie jak w Pascalu i BASICu)
* Przerwij działanie programu naciskaj c kombinacj klawiszy while - dopóki
[Ctrl]+[Break] lub [Ctrl]+[C]. do - wykonuj
* Sprawd , jaki jest katalog wyj ciowy kompilatora. if - je eli
27
break - przerwij wykonywanie p tli p tki for, lecz przerwa p tl w jej wn trzu (po osi gni ciu
continue - kontynuuj p telkowanie okre lonego stanu) przy pomocy rozkazu break:
goto - skocz do wskazanej etykiety
________________________________________________________________ [LOOP-6]
Nasz program mógłby przy zastosowaniu tych słów zosta napisany #include <iostream.h>
np. tak: int main(void)
{
[LOOP-1] for(;;)
{
#include <iostream.h> cout << x << '\n';
void main() x++;
{ if( x > 10) break;
int x = 2; }
petla: return 0;
cout << x << '\n'; }
x = x + 1;
if (x < 11) goto petla; Wszytkie te p tle (sprawd !) b d działa tak samo. Spróbuj przy
}
ich pomocy, zanim przejdziesz dalej, wydrukowa np. liczby od 10
Mo emy zastosowa rozkaz goto w postaci skoku bezwarunkowego, a
p telkowanie przerwa rozkazem break: do 100 i wykonaj jeszcze kilka innych eksperymentów.
Dokładniejszy opis znajdziesz w dalszej cz ci ksi ki, ale
[LOOP-2] przykład - to przykład.
W nast pnym programie zilustrujemy działanie wszystkich pi ciu [F7] - for(i=1; i<6; i++);
operatorów inkrementacji (dekrementacja to te inkrementacja
tylko w przeciwn stron ). * Naprowad kursor na zmienn d w tek cie programu i wykonaj
inspekcj powtórnie [Alt]-[D], [I]. Jak widzisz w okienku
[P019.CPP] zmiennej d została nadana warto 100. Naci nij [Esc].
* Zliczanie ilo ci wykonanych przez program p tli. [S!] constant/variable - STAŁA czy ZMIENNA.
________________________________________________________________
int i; (deklaracja, e i b dzie zmienn całkowit ) const - (CONSTant) - stała. Deklaracja stałej, słowo kluczowe w
... j zyku C.
i=1; (zainicjowanie zmiennej, nadanie pocz tkowej warto ci) var - (VARiable) - zmienna. W j zyku C przyjmowane domy lnie.
... Słowo var (stosowane w Pascalu) NIE JEST słowem kluczowym j zyka
i++; (powi kszanie i o 1 w ka dej p tli)
... C ani C++ (!).
i<6 (warunek kontynuacji) ________________________________________________________________
Skutek praktyczny:
* Mo liwo grupowej deklaracji zmiennych tego samego typu: * Ma sens i jest poprawna deklaracja:
int b,c,d,e; const float PI = 3.1416;
* Niepoprawna natomiast jest deklaracja:
[Z] var float x;
________________________________________________________________ Je li nie zadeklarowano stałej słowem const, to "zmienna" (var)
4. Zmie w programie przykładowym warto pocz tkow STO na przyjmowana jest domy lnie.
dowoln inn - np. zero. Przetestuj działanie programu.
5. Sprawd , czy mo na wszystkie zmienne u ywane w programie Definicja powoduje nie tylko okre lenie, jakiego typu
przykładowym zadeklarowa wspólnie (jeden wiersz zamiast warto ciami mo e operowa dana zmienna b d funkcja, która
trzech). zostaje od tego momentu skojarzona z podanym identyfikatorem,
________________________________________________________________ ale dodatkowo powoduje:
* w przypadku zmiennej - przypisanie jej warto ci,
* W przypadku funkcji - przyporz dkowanie ciała funkcji.
Zdefiniujmy dla przykładu kilka własnych funkcji.
LEKCJA 11. Jak deklarowa zmienne. Co to jest wska nik.
________________________________________________________________ Przykład:
UWAGI:
Po instalacji BORLAND C++/Turbo C++ standardowo jest przyjmowany * DB - define byte - zdefiniuj bajt;
DW - define word - zdefiniuj słowo (16 bitów);
33
DD - double word - podwójne słowo (32 bity); STDIO.H i CONIO.H.
DF, DP - define far pointer - daleki wska nik w 386;
DQ - quad word - poczwórne słowo (4 * 16 = 64 bity); [P021.CPP]
DT - ten bytes - dziesi bajtów. //UWAGA: Doł cz wła ciwe pliki nagłówkowe !
* zwró uwag , e typ wyliczeniowy enum wyst puje jako odr bny
typ danych (szczegóły w dalszej cz ci ksi ki). void main()
________________________________________________________________ {
float A, B;
clrscr();
scanf("%f %f", &A, &B);
Poniewa nie ma liczb ani short float, ani unsigned short float, printf("\n%f\t%d", A,B);
getch();
słowo int mo e zosta opuszczone w deklaracji. Poprawne s zatem }
deklaracje: [Z]
________________________________________________________________
short a; 3 Zmie w programie przykładowym, w funkcji printf() wzorce
unsigned short b; formatu na %s, %c, itp. Porównaj wyniki.
________________________________________________________________
Zapis +-3.4E-38...3.4E+38 oznacza:
-3.4*10^+38...0...+3.4*10^-38...+3.4*10^+38 Adres w pami ci to taka sama liczba, jak wszystkie inne i wobec
Dopuszczalne s deklaracje i definicje grupowe z zastosowaniem tego mo na ni manipulowa . Adresami rz dz jednak do
listy zmiennych. Zmienne na li cie nale y oddzieli przecinkami: specyficzne prawa, dlatego te w j zyku C++ wyst puje jeszcze
jeden specjalny typ zmiennych - tzw. ZMIENNE WSKAZUJ CE (ang.
int a=0, b=1, c, d; pointer - wska nik). Twoja intuicja podpowiada Ci zapewne, e s
float PI=3.14, max=36.6;
to zmienne całkowite (nie ma przecie komórki pami ci o adresie
Po wi cimy teraz chwil drugiej funkcji, któr ju wielokrotnie 0.245 ani 61/17). Poj cia "komórka pami ci" a nie np. "bajt"
stosowali my - funkcji wej cia - scanf(). u ywam wiadomie, poniewa obszar zajmowany w pami ci przez
zmienn mo e mie ró n długo . Aby komputer wiedział ile
FUNKCJA scanf(). kolejnych bajtów pami ci zajmuje wskazany obiekt (liczba długa,
krótka, znak itp.), deklaruj c wska nik trzeba poda na co
Funkcja formatowanego wej cia ze standardowego strumienia b dzie wskazywał. W sposób "nieoficjalny" ju w funkcji scanf
wej ciowego (stdin). Funkcja jest predefiniowana w pliku STDIO.H korzystali my z tego mechanizmu. Jest to zjawisko specyficzne
dla j zyka C++, wi c zajmijmy si nim troch dokładniej.
i korzystaj c z funkcji systemu operacyjnego wczytuje dane w
postaci tekstu z klawiatury konsoli. Interpretacja pobranych POJ CIE ZMIENNEJ WSKAZUJ CEJ I ZMIENNEJ WSKAZYWANEJ.
przez funkcj scanf znaków nast pi zgodnie z yczeniem
programisty okre lonym przez zadany funkcji format (%f, %d, %c Wska nik to zmienna, która zawiera adres innej zmiennej w
itp.). Wywołanie funkcji scanf ma posta : pami ci komputera. Istnienie wska ników umo liwia po rednie
odwoływanie si do wskazywanego obiektu (liczby, znaku, ła cucha
scanf(Format, Adres_zmiennej1, Adres_zmiennej2...);
znaków itp.) a tak e stosunkowo proste odwołanie si do obiektów
dla przykładu
s siaduj cych z nim w pami ci. Załó my, e:
scanf("%f%f%f", &X1, &X2, &X3);
x - jest umieszczon gdzie w pami ci komputera zmienn
wczytuje trzy liczby zmiennoprzecinkowe X1, X2 i X3. całkowit typu int zajmuj c dwa kolejne bajty pami ci, a
Format decyduje, czy pobrane znaki zostan zinterpretowane np. px - jest wska nikiem do zmiennej x.
jako liczba całkowita, znak, ła cuch znaków (napis), czy te w
inny sposób. Od sposobu interpretacji zale y i rozmieszczenie Jednoargumentowy operator & podaje adres obiektu, a zatem
ich w pami ci i pó niejsze "si gni cie do nich", czyli odwołanie instrukcja:
Zwró uwag , e podaj c nazwy (identyfikatory) zmiennych nale y przypisuje wska nikowi px adres zmiennej x. Mówimy, e:
poprzedzi je w funkcji scanf() operatorem adresowym [&].
Zapis: px wskazuje na zmienn x lub
px jest WSKA NIKIEM (pointerem) do zmiennej x.
int X;
... Jednoargumentowy operator * (naz. OPERATOREM WYŁUSKANIA)
scanf("%d", &X); powoduje, e zmienna "potraktowana" tym operatorem jest
traktowana jako adres pewnego obiektu. Zatem, je li przyjmiemy,
oznacza, e zostan wykonane nast puj ce działania: e y jest zmienn typu int, to działania:
* Kompilator zarezerwuje 2 bajty pomi ci w obszarze pami ci
danych programu na zmienn X typu int; y = x;
* W momencie wywołania funkcji scanf funkcji tej zostanie
przekazany adres pami ci pod którym ma zosta umieszczona oraz
zmienna X, czyli tzw. WSKAZANIE DO ZMIENNEJ;
* Znaki pobrane z klawiatury przez funkcj scanf maj zosta px = &x;
przekształcone do postaci wynikaj cej z wybranego formatu %d - y = *px;
tzn. do postaci zajmuj cej dwa bajty liczby całkowitej ze
znakiem. b d mie identyczny skutek. Zapis y = x oznacza:
"Nadaj zmiennej y dotychczasow warto zmiennej x";
[???] A JE LI PODAM INNY FORMAT ? a zapis y=*px oznacza:
________________________________________________________________ "Nadaj zmiennej y dotychczasow warto zmiennej, której adres w
C++ wykona Twoje rozkazy najlepiej jak umie, niestety nie
sprawdzaj c po drodze formatów, a z zer i jedynek zapisanych w pami ci wskazuje wska nik px" (czyli wła nie x !).
pami ci RAM aden format nie wynika. Otrzymasz bł dne dane.
________________________________________________________________ Wska niki tak e wymagaj deklaracji. Poprawna deklaracja w
opisanym powy ej przypadku powinna wygl da tak:
Poni ej przykład skutków bł dnego formatowania. Doł cz pliki
34
int x,y; Zwró uwag , e kolejno {L<<-R} dotyczy WSZYSTKICH operatorów
int *px; jednoargumentowych.
main() ________________________________________________________________
......
Zapis int *px; oznacza: Je li dwa wska niki wskazuj zmienne takiego samego typu, np. po
"px jest wska nikiem i b dzie wskazywa na liczby typu int".
zadeklarowaniu:
Wska niki do zmiennych mog zamiast zmiennych pojawia si w
wyra eniach po PRAWEJ STRONIE, np. zapisy: int *pX, *pY;
int X, Y;
int X,Y;
int *pX; i zainicjowaniu:
...
pX = &X; pX = &X; pY = &Y;
.......
Y = *pX + 1; /* to samo, co Y = X + 1 */ mo na zastosowa operator przypisania:
printf("%d", *pX); /* to samo, co printf("%d", X); */
Y = sqrt(*pX); /* pierwiastek kwadrat. z X */ pY = pX;
......
Spowoduje to skopiowanie warto ci (adresu) wska nika pX do pY,
s w j zyku C++ poprawne. dzi ki czemu od tego momentu wska nik pY zacznie wskazywa
zmienn X. Zwró uwag , e nie oznacza to bynajmniej zmiany
Zwró uwag , e operatory & i * maj wy szy priorytet ni warto ci zmiennych - ani wielko c X, ani wielko Y, ani ich
operatory arytmetyczne, dzi ki czemu adresy w pami ci NIE ULEGAJ ZMIANIE. Zatem działanie
* najpierw nast puje pobranie spod wskazanego przez instrukcji:
wska nik adresu zmiennej;
* potem nast puje wykonanie operacji arytmetycznej; pY = pX; i *pY = *pX;
(operacja nie jest wi c wykonywana na wska niku, a na
wskazywanej zmiennej!). jest RÓ NE a wynika to znowu z priorytetu operatorów:
W j zyku C++ mo liwa jest tak e sytuacja odwrotna: najpierw * wyłuskanie zmiennych spod podanych adresów,
potem = przypisanie warto ci (ale ju zmiennym a nie
Y = *(pX + 1); wska nikom!)
Poniewa operator () ma wy szy priorytet ni * , wi c: C++ ch tnie korzysta ze wskazania adresu przy przekazywaniu
danych - parametrów do/od funkcji.
najpierw wska nik zostaje zwi kszony o 1;
potem zostaje pobrana z pami ci warto znajduj ca si pod Asekuruj c si na całej linii i podkre laj c, e nie zawsze
wskazanym adresem (w tym momencie nie jest to ju adres zmiennej wygl da to tak prosto i ładnie, posłu si do zademonstrowania
działania wska ników przykładowym programem. Wpisz i uruchom
X, a obiektu "nast pnego" w pami ci) i przypisana zmiennej Y. nast puj cy program:
3. Ustawiamy oba wska niki tak by wskazywały adres w pami ci [???] CO Z TYMI OBIEKTAMI ?
pierwszej liczby a=11. ________________________________________________________________
4. Zwi kszamy oba wska niki i sprawdzamy, co wskazuj . OBIEKTEM w szerokim znaczeniu tego słowa jest ka da liczba,
znak, ła cuch znaków itp.. Takimi klasycznymi obiektami j zyki
Je li kompilator rozmie ci nasze zmienne w kolejnych komórkach programowania operowały ju od dawien dawna. Prawdziwe
pami ci, to powinni my uzyska nast puj cy wydruk: programowanie obiektowe w dzisiejszym, w szym znaczeniu
rozpoczyna si jednak tam, gdzie obiektem mo e sta si tak e
Skok o 2B Skok o 4B co "nietypowego" - np. rysunek. Jest to jednak wła ciwy chyba
11 11 moment, by zwróci Ci uwag , e z punktu widzenia komputera
22 33 obiekt to co , co zajmuje pewien obszar pami ci i z czym wiadomo
33 55 jak post powa .
44 77 ________________________________________________________________
55 99
66 27475 Deklaracja:
77 28448
88 8258 int A[12];
99 27475 oznacza:
10 2844 nale y zarezerwowa 12 KOLEJNYCH komórek pami ci dla 12 liczb
całkowitych typu int (po 2 bajty ka da). Jednowymiarowa tablica
Zwró uwag , e to deklaracja wska nika decyduje, co praktycznie (wektor) b dzie si nazywa "A", a jej kolejne elementy zostan
ponumerowane przy pomocy indeksu:
oznacza operacja *(ptr + 1). W pierwszym przypadku wska nik - zwró uwag , e w C zaczynamy liczy OD ZERA A NIE OD JEDYNKI;
powi ksza si o 2 a w drugim o 4 bajty. Te odpowiednio 2 i 4
bajty stanowi długo komórki pami ci lub precyzyjniej, pola
pami ci przeznaczonego dla zmiennych okre lonego typu. A[0], A[1], A[2], A[3], .... A[11].
Warto ci pojawiaj ce si w drugiej kolumnie po 99 s
przypadkowe i u Ciebie mog okaza si inne. Je li chcemy zadeklarowa :
- indeks i;
C++ pozwala wska nikom nie tylko wskazywa adres zmiennej w - wska nik, wskazuj cy nam pocz tek (pierwszy, czyli zerowy
pami ci. Wska nik mo e równie wskazywa na inny wska nik. Takie element) tablicy;
- sam tablic ;
wskazania: to takie deklaracje powinny wygl da nast puj co:
s równowa ne. Podobnie identyczne znaczenie maj zapisy: Dla przykładu, skompiluj program przykładowy. Zwró uwag na
sposób zainicjowania wska nika.
x = &A[i] x=A+i
*pA[i] *(A+i) [P023.CPP]
Nale y jednak podkre li , e pomi dzy nazwami tablic (w naszym # include "stdio.h"
przykładzie A) a wska nikami istnieje zasadnicza ró nica. # include <conio.h>
Wska nik jest ZMIENN , zatem operacje: int a[][2]={ {1,2},{3,4},{5,6},{7,8},{9,10},{11,12} };
char b[]={ "Poniedzialek" };
pA = A; int i;
pA++; int *pa;
char *pb;
s dopuszczalne i sensowne. Nazwa tablicy natomiast jest STAŁ ,
zatem operacje: void main()
{
A = pA; LE ! pa = &a[0][0];
A++; LE ! pb = b; // lub pb = b[0];
clrscr();
s niedopuszczalne i próba ich wykonania spowoduje bł dy ! for (i=0; i<12; i++)
printf("%d\t%c\n", *(pa+i), *(pb+i));
DEKLAROWANIE I INICJOWANIE TABLIC. getch();
}
Elementom tablicy, podobnie jak zmiennym mo emy nadawa
watro ci. Warto ci takie nale y podawa w nawiasach klamrowych, Zwró uwag , e w C++ ka dy wymiar tablicy musi mie swoj par
a wielko tablicy - w nawiasach kwadratowych. nawiasów kwadratowych. Dla przykładu, tablic trójwymiarow
nale y deklarowa nie tak TAB3D[i, j, k] lecz tak:
Przykład
int i, j, k;
int WEKTOR[5]; ...
Tablica WEKTOR jest jednowymiarowa i składa si z 5 elementów TAB3D[i][j][k];
typu int: WEKTOR[0]....WEKTOR[4].
Jest w dobrym stylu panowa nad swoimi danymi i umieszcza je w
Przykład tzw. BUFORACH, czyli w wydzielonych obszarach pami ci o znanym
adresie, wielko ci i przeznaczeniu. W nast pnym programie
float Array[10][5]; przykładowym utworzymy taki bufor w postaci tablicy bufor[20] i
Tablica Array jest dwuwymiarowa i składa si z 50 elementów typu zastosujemy zamiast funkcji scanf() czytaj cej bezpo rednio z
klawiatury par funkcji:
float: Array[0][0], Array[0][1]......Array[0][4]
Array[1][0], Array[1][1]......Array[1][4] gets() - GET String - pobierz ła cuch znaków z klawiatury do
........................................... bufora;
Array[9][0], Array[9][1]......Array[9][4] sscanf(bufor) - odczytaj z bufora (z pami ci).
const int b[4]={1,2,33,444}; Dokładniej p tl for omówimy w trakcie nast pnej lekcji.
Elementom jednowymiarowej tablicy (wektora) b przypisano Poniewa mam nadziej , e "podstawow " posta p tli for
warto i: b[0]=1; b[1]=2; b[2]=33; b[3]=444; pami tasz z przykładów LOOP-n:
Poni ej troch bardziej "elegancka wersja" z zastosowaniem p tli TABLICA[i][j] = (i+1)*10 + (j+1);
gets(bufor); [P026.CPP]
sscanf(bufor, "%d", &liczba);
int TABLICA[4][6]={{11,12,13,14,15,16},{21,22,23,24,25,26},
while (liczba != 0) {31,32,33,34,35,36},{41,42,43,44,45,46}};
{ # include <stdio.h>
suma += liczba; # include <conio.h>
gets(bufor); int *pT;
sscanf(bufor, "%d", &liczba); int i, j;
if(liczba == 0) void main()
printf("I to by bylo na tyle...\n"); {
else clrscr();
ile++; printf("OTO NASZA TABLICA \n");
} for (i=0; i<=3; i++)
printf("Suma wynosi: %d\n", suma); {
printf("Srednia wynosi: %d\n", suma / ile); for (j=0; j<=5; j++)
getch(); printf("%d\t", TABLICA[i][j]);
} printf("\n");
}
Program powy szy, cho operuje tablic , robi to troch jakby za printf("\n\Inicjujemy wska nik na poczatek tablicy\n");
kulisami. Utwórzmy zatem inn - bardziej "dydaktyczn " tablic , printf("i INKREMENTUJEMY wska nik *pT++ \n");
której elementy byłyby łatwo rozpoznawalne.
pT=&TABLICA[0][0];
PRZYKŁADY TABLIC WIELOWYMIAROWYCH. for (i=0; i<4*6; i++)
printf("%d ", *(pT+i));
Dzi ki matematyce bardziej jeste my przyzwyczajeni do zapisu
tablic w takiej postaci: getch();
}
a11 a12 a13 a14 a15 a16
a21 a22 a23 a24 a25 a26 Zwró uwag , e je li tablica ma wymiary A * B (np. 3 * 4) i
a31 a32 a33 a34 a35 a36 składa si z k=A*B elementów, to w C++ zakres indeksów wynosi
a41 a42 a43 a44 a45 a46 zawsze 0, 1, 2, .....A*B-2, A*B-1. Tak wi c tablica 10 x 10
(stuelementowa) b dzie składa si z elementów o numerach
gdzie a i,j /** indeks**/ oznacza element tablicy zlokalizowany 0...99, a nie 1...100.
w:
- wierszu i [P027.CPP]
- kolumnie j
Przypiszmy kolejnym elementom tablicy nast puj ce warto ci: # include <stdio.h>
# include <conio.h>
11 12 13 14 15 16 int TABLICA[4][6];
21 22 23 24 25 26 int *pT;
31 32 33 34 35 36 int i, j;
41 42 43 44 45 46
void main()
Jest to tablica dwuwymiarowa o wymiarach 4WIERSZE X 6KOLUMN, {
czyli krócej 4X6. Liczby b d ce elementami tablicy s typu clrscr();
całkowitego. Je li zatem nazwiemy j TABLICA, to zgodnie z printf("Inicjujemy tablice\n");
zasadami przyj tymi w j zyku C/C++ mo emy j zadeklarowa : for (i=0; i<4; i++)
38
for (j=0; j<6; j++) dwucyfrowych dwie spacje. Po dziesi ciu kolejnych wynikach
{ TABLICA[i][j] = (i+1)*10 + (j+1); } // INDEKS! trzeba wstawi znak nowego wiersza. Sprawdzamy te warunki:
printf("OTO NASZA TABLICA \n");
for (i=0; i<=3; i++) if (*(pT+k) < 10) - je li wynik jest mniejszy ni 10...
{ lub if (T[i][j] < 10);
for (j=0; j<=5; j++) if ((k+1) % 10 == 0) - je li k jest całkowit wielokrotno ci
printf("%d\t", TABLICA[i][j]); 10, czyli - je li reszta z dzielenia równa si zero...
printf("\n");
} Zastosowane w powy szych programach nawiasy klamrowe {}
printf("\n\Inicjujemy wska nik na poczatek tablicy\n"); spełniaj rol INSTRUKCJI GRUPUJ CEJ i pozwalaj podobnie jak
printf("i INKREMENTUJEMY wska nik *pT++ \n"); para BEGIN...END w Pascalu zamkn w p tli wi cej ni jedn
pT=&TABLICA[0][0]; instrukcj . Instrukcje uj te w nawiasy klamrowe s traktowane
for (i=0; i<4*6; i++) jak pojedyncza instrukcja prosta.
printf("%d ", *(pT+i));
Tablice mog zawiera liczby, ale mog zawiera tak e znaki.
getch(); Przykład prostej tablicy znakowej zawiera nast pny program
} przykładowy.
Do pełni szcz cia brak jeszcze wska nika do tablicy: char *pT;
int i, j, k;
int *pT; char spacja=' ';
void main()
i jego zainicjowania {
clrscr();
pT = &T[0][0]; pT =&T[0][0];
printf("\t TABLICA znakowa (ineksy)\n\n");
I ju mo emy zaczyna . Mogliby my oczywi cie zainicjowa tablic
for (i=0; i<7; i++)
"na piechot ", ale to i nieeleganckie, i pracochłonne, i o {
pomyłk łatwiej. Pami taj, e komputer myli si rzadziej ni for (j=0; j<12; j++)
programista, wi c zawsze lepiej jemu zostawi mo liwie jak printf("%c ", T[i][j] );
najwi cej roboty. printf("\n");
}
[P028.CPP] printf("\n\t Przy pomocy wska nika \n\n");
void main()
LEKCJA 13. Jak tworzy w programie p tle i rozgał zienia. {
_______________________________________________________________ int n;
W trakcie tej lekcji: for (n=0; n<=100; n++) printf("%f\t", sqrt(n));
1. Dowiesz si znacznie wi cej o p tlach. getch();
2. Przeanalizujemy instrukcje warunkowe i formułowanie warunków. }
_______________________________________________________________ Wyra enie inicjuj ce mo e zosta pomini te. Innymi słowy zmienna
Zaczniemy t lekcj nietypowo - od słownika, poniewa dobrze mo e zosta zainicjowana na zewn trz p tli, a p tla przejmie j
jest rozumie dokładnie co si pisze. Tym razem słownik jest tak jaka jest w danym momencie. Przykładowo:
troch obszerniejszy. Pozwalam sobie przytoczy niektóre słowa .....
powtórnie - dla przypomnienia i Twojej wygody. Do organizacji {
p tli b d nam potrzebne nast puj ce słowa: float n;
n=(2*3)/(3*n*n - 1.234);
[S!] conditional expressions - wyra enia warunkowe ......
structural loops - p tle strukturalne for (; n<=100; n++) printf("%f4.4\t", sqrt(n));
________________________________________________________________
if - je eli (poprzedza warunek do sprawdzenia); Przykład:
else - a je li nie, to (w przeciwnym wypadku...);
for - dla; Warunek przerwania p tli mo e mie tak e inny charakter. W
while - dopóki (dopóki nie spełnimy warunku); przykładzie p tla zostanie przerwana, je li ró nica pomi dzy
do - wykonaj, wykonuj; kolejnymi pierwiastkami przekroczy 3.0.
break - przerwij (wykonanie p tli);
switch - przeł cz; void main()
case - przypadek, wariant (jedna z mo liwo ci); {
goto - id do... float y=0, n=0;
default - domy lny, (automatyczny, pozostały); for (; (sqrt(n)-y)<=3.0; n++)
continue - kontynuuj (p tl ); { y=sqrt(n);
________________________________________________________________ printf("%f2.3\t", y);
UWAGA: W C/C++ nie stosuje si słowa THEN. }
getch();
P TLA TYPU for. }
Wska nik w charakterze zmiennej roboczej w p tli typu for. P tla Umo liwia to dynamiczne inicjowanie tablic pod warunkiem
rygorystycznego przestrzegania zasady, e do zainicjowana stałej
powoduje wypisanie napisu.
mo emy zastosowa wył cznie wyra enie stałowarto ciowe. .
char *Ptr = "Jakis napis";
void main() [S] sizeof - wielko w bajtach.
{
for (; (*Ptr) ;) DANE PREDEFINIOWANE.
41
Dla ułatwienia ycia programi cie producenci kompilatorów C++ void main()
stosuj stałe predefiniowane w plikach nagłówkowych, np.: {
do
_stklen - wielko stosu, {printf(".");}
O_RDONLY - tryb otwarcia pliku "tylko do odczytu", while (!kbhit());
GREEN - numer koloru w palecie, itp., itp. printf("Koniec petli....");
}
Predefiniowanych stałych mo emy u ywa do deklarowania
indeksów/rozmiarów tablic. INSTRUKCJA WARUNKOWA if, if...else i if...else...if..
Przykład inaczej:
Stosujemy p tl while w programie obliczaj cym sum . if(a>0) {if(a<100) printf("Dwucyfrowa"); else printf("100+");}
[S!] DOS API function names - nazwy funkcji z interfejsu DOS Przykład:
________________________________________________________________
sound - d wi k; register int i;
delay - opó nienie, zwłoka; .....
nosound - bez d wi ku (wył cz d wi k); for (i=1; i<1000; i++) {.....}
________________________________________________________________
ZMIENNE ZEWN TRZNE - extern.
[Z]
________________________________________________________________ Je li zmienna została - raz i TYLKO RAZ - zadeklarowana w
1. Bior c pod uwag , e iloraz cz stotliwo ci kolejnych d wi ków pojedynczym segmencie du ego programu, zostanie w tym e
segmencie umieszczona w pami ci i potraktowana podobnie do
jest stały tzn. Fcis/Fc=Ffis/Ff=....=const oraz, e oktawa to zmiennych typu static. Po zastosowaniu w innych segmentach
podwojenie cz stotliwo ci, opracuj program i oblicz deklaracji extern zmienna ta mo e by dost pna w innym segmencie
cz stotliwo ci poszczególnych d wi ków.
2. Spróbuj zastosowa w programie przykładowym kolejno p tle programu.
for, while, do...while.
3. Zastosuj we własnym programie do wiadczalnym instrukcj Przykład: extern int NUMER;
switch.
STRUKTURY.
LEKCJA 14. Jak tworzy i stosowa struktury. Poznane wcze niej tablice mog zawiera wiele danych, ale
wszystkie te dane musz by tego samego typu. Dla zgrupowania
________________________________________________________________ powi zanych ze sob logicznie danych ró nego typu C/C++ stosuje
STRUKTURY, deklarowane przy pomocy słowa struct. Kolejne pola
W trakcie tej lekcji poznasz poj cia: struktury s umieszczane w pami ci zgodnie z kolejno ci ich
* Klasy zmiennej. deklarowania. Struktur , podobnie jak zmienn , MUSIMY
* Struktury. ZADEKLAROWA . Struktura jest objektem bardziej zło onym ni
* Pola bitowego. pojedyncza zmienna, wi c i deklaracja struktury jest bardziej
* Unii. skomplikowana. Deklaracja struktury składa si z nast puj cych
Dowiesz si tak e wi cej o operacjach logicznych. elementów:
________________________________________________________________
1. Słowo kluczowe struct (obowi zkowe).
2. Nazwa (opcjonalna). Je li podamy nazw , to nazwa ta b dzie
CO TO JEST KLASA ZMIENNEJ? oznacza dany typ struktury.
3. Nawias klamrowy {
W j zyku C i C++ programista ma wi kszy wpływ na rozmieszczenie 4. Deklaracje kolejnych składników struktury.
zmiennych w pami ci operacyjnej komputera i w rejestrach 5. Nawias klamrowy }
mikroprocesora. Mo e to mie decyduj cy wpływ na dost pno 6. Lista nazw struktur okre lonego powy ej typu (mo e zosta
danych z ró nych miejsc programu i szybko działania programu. zadeklarowana oddzielnie).
Nale y podkre li , e TYP ZMIENNEJ (char, int, float itp.)
decyduje o sposobie interpretacji przechowywanych w pami ci zer Przykład. Deklaracja ogólnego typu struktury i okre lenie
i jedynek, natomiast KLASA ZMIENNEJ decyduje o sposobie wewn trznej postaci struktury.
przechowywania zmiennej w pami ci. W C++ wyst puj cztery klasy
zmiennych. struct Ludzie
{
ZMIENNE STATYCZNE - static. char Imiona[30];
char Nazwisko[20];
Otrzymuj stał lokalizacj w pami ci w momencie uruchamiania int wiek;
programu. Zachowuj swoj warto przez cały czas realizacji char pokrewienstwo[10]
programu, chyba, e wiadomie za damy zmiany tego stanu - np. };
instrukcj przypisania.
Przykład deklaracji: static float liczba; Je li okre limy ju typ struktury - czyli rodzaj, wielko i
przeznaczenie poszczególnych pól struktury, mo emy dalej tworzy
W wi kszo ci kompilatorów C++ zmienne statyczne, które nie
zostały jawnie zainicjowane w programie, otrzymuj po - deklarowa i inicjowa konkretne struktury danego typu.
zadeklarowaniu warto ZERO.
44
Przykład. Deklaracja zmiennych - struktur tego samego typu.
return 0;
struct Ludzie Moi, Twoi, Jego, Jej, Szwagra; }
Deklaracj struktur mo na poł czy . Tablice mog by elementami struktur, ale i odwrotnie - ze
struktur, jak z cegiełek mo na tworzy konstrukcje o wy szym
Przykład. Poł czona deklaracja struktur. stopniu zło ono ci - struktury struktur i tablice struktur.
Je li tablica składa si z liczb typu int, to deklarujemy j :
struct Ludzie
{ char pokrewienstwo[10]; int TABLICA[10];
char Imiona[30];
int wiek; je li tablica składa si ze struktur, to deklarujemy j :
} Moi, Twoi, Szwagra;
struct TABLICA[50];
Struktury statyczne
W przykładzie poni ej przedstawiono
* maj stałe miejsce w pami ci w trakcie całego programu;
* s "widoczne" i dost pne w całym programie. * deklaracj jednowymiarowej tablicy LISTA[50],
* elementami tablicy s struktury typu SCzlowiek,
Zadeklarujemy teraz typ struktury i zainicjujemy dwie struktury. * jednym z elementów ka dej struktury SCzlowiek jest struktura
"ni szego rz du" typu Adres;
Do struktury w cało ci mo emy odwoływa si za pomoc jej nazwy struct SCzlowiek LISTA[50];
a do poszczególnych elementów struktury poprzez nazw struktury
i nazw pola struktury - ROZDZIELONE KROPK ".". Zademonstrujmy LISTA[1].Wiek=34;
to na przykładzie. Zwró uwag na ró ne sposoby przekazywania LISTA[1].Mieszkanie.Nr_Domu=29;
danych pomi dzy strukturami: printf("%d", LISTA[1].Mieszkanie.Nr_Domu);
Wska niki mog wskazywa struktur w cało ci lub element * płe 0 - m czyzna, 1 - kobieta ( 1 bit );
struktury. J zyk C/C++ oferuje specjalny operator -> który * wiek 0 - 255 lat (8 bitów);
pozwala na odwoływanie si do elementów struktury. W przykładzie * ilo dzieci 0 - 15 (4 bity);
* kolejny numer mał e stwa 0 - 7 (3 bity);
poni ej przedstawiono ró ne sposoby odwołania si do elementów
trzech identycznych struktur STA, STB, STC. to przecie wszystkie te informacje mog nam si zmie ci w
jednym szesnastobitowym rejestrze lub w dwu bajtach pami ci.
[P039.CPP] Takie kilka bitów wydzielone i maj ce okre lone znaczenie to
wła nie pole bitowe. C++ pozwala tak e na uwzgl dnianie znaku w
int main() polach bitowych. Pola bitowe mog by typu int i unsigned int
{ (czyli takie jak w przykładzie poni ej). Je li jakie dane
chcemy przechowywa w postaci pola bitowego, w deklaracji
struct struktury sygnalizujemy to dwukropkiem. Stwarza to dwie istotne
{ mo liwo ci:
char Tekst[20]; * bardziej ekonomicznego wykorzystania pami ci;
int Liczba1; * łatwego dodatkowego zaszyfrowania danych.
float Liczba2;
} STA, STB, STC, *Pointer; [P040.CPP]
Elementami struktury mog by zmienne dowolnego typu, ł dznie z Poni ej przedstawiam przykład pola bitowego zajmuj cego trzy
innymi strukturami. kolejne słowa 16 bitowe. Dodanie pola pustego wymusza
rozpocz cie pola pole_IV od pocz tku trzeciego słowa maszynowego
Ciekawostka:
________________________________________________________________ (zakładamy, e pracujemy z komputerem 16 bitowym).
Wska nik do deklarowanej struktury mo e by w j zyku C/C++ jak
jeden z jej WŁASNYCH elementów. Je li wska nik wchodz cy w skład struct
{
struktury wskazuje na WŁASN struktur , to nazywa si to unsigned pole_I:4;
AUTOREFERENCJ STRUKTURY. unsigned pole_II:10;
________________________________________________________________ unsigned pole_III:4;
unsigned :0; /* to jest pole puste */
POLA BITOWE. unsigned pole_IV:5;
} pole_przykladowe;
Cz sto zdarza si , e jaka zmienna ma zaw ony zakres warto ci.
Zwró uwag , e cz bitów w drugim i trzecim słowie maszynowym
Dla przykładu zmienne logiczne (tzw. flagi) to zawsze tylko 0
46
nie zostanie wykorzystana.
Miło byłoby poogl da to troch dokładniej w przykładowych
UNIE czyli ZMIENNE WARIANTOWE. programach, ale potrzebne nam do tego b d funkcje. Zajmijmy si
wi c uwa niej funkcjami.
Unie to specyficzne struktury, w których pola pami ci
przeznaczone na objekty ró nego typu nakładaj si . Je li jaka
zmienna mo e by reprezentowana na kilka sposobów (wariantów) to LEKCJA 15. Jak posługiwa si funkcjami.
________________________________________________________________
sensowne jest przydzielenie jej nie struktury a unii. W danej
chwili pole pami ci nale ce do unii mo e zawiera TYLKO JEDEN W trakcie tej lekcji dowiesz si wi cej o:
WARIANT. W przykładzie - albo cyfr (która znakowo jest widziana * funkcjach i prototypach funkcji;
* przekazywaniu argumentów funkcji;
jako znak ASCII o kodzie 2,3,4 itd.) albo napis. Do * współpracy funkcji ze wska nikami.
zadeklarowania unii słu y słowo kluczowe union. _______________________________________________________________
P tla w przykładzie nie ma znaczenia. Słu y tylko dla Twojej char odp;
wygody - dzi ki niej nie musisz uruchamia programu
przykładowego wielokrotnie. Podobnie zmienne BUFOR oraz i maj int main()
znaczenie pomocnicze. Zwró uwag , e nieprawidłowa {
interpretacja zawarto ci pola unii mo e spowodowa wadliwe int X, Y;
działanie programu. clrscr();
printf("\nPodaj dwie liczby calkowite od -32768 do +32767\n");
[Z] printf("\nLiczby X i Y rozdziel spacja");
________________________________________________________________ printf("\nPo podaniu drugiej liczby nacisnij [Enter]");
1. W programie przykładowym zamie uni na struktur . Porównaj printf("\nLiczby ujemne sa w kodzie dopelniajacym");
działanie. printf("\nskrajny lewy bit oznacza znak 0-Plus, 1-Minus");
2 Przydziel na Wiek w strukturze Facet o jeden bit mniej. Ile for(;;)
lat mo e teraz mie Facet ? {
3. Zmodyfikuj program przykładowy tak, by napis o liczbie printf("\n");
m ów/ on zale ał od płci - pola Sex. scanf("%d %d", &X, &Y);
4. Zamieniwszy uni na struktur w programie, sprawd , czy printf("\nX:\t"); Demo(X);
wpływa to na wielko pliku *.EXE. printf("\nY:\t"); Demo(Y);
________________________________________________________________ printf("\n~Y:\t"); Demo(~Y);
printf("\nX&Y:\t"); Demo(X&Y);
OPERACJE LOGICZNE. printf("\nX|Y:\t"); Demo(X|Y);
printf("\nX^Y:\t"); Demo(X^Y);
Zaczniemy od operacji logicznych na pojedynczych bitach liczb printf("\nY:\t"); Demo(Y);
całkowitych. W C++ mamy do dyspozycji nast puj ce operatory: printf("\nY>>1:\t"); Demo(Y>>1);
printf("\nY<<2:\t"); Demo(Y<<2);
~ Zaprzeczenie (NOT) ~0=1; ~1=0; printf("\n\n Jeszcze raz? T/N");
| Suma (OR) 0|0=0; 0|1=1; 1|0=1; 1|1=1; odp=getch();
& Iloczyn (AND) 0&0=0; 0&1=0; 1&0=0; 1&1=1; if (odp!='T'&& odp!='t') break;
^ Alternatywa wył czna ALBO...ALBO (XOR) }
0^0=0; 0^1=1; 1^0=1; 1^1=0; return 0;
<< Przesuni cie bitów w lewo (Shift Left) }
<< 00001000 = 00010000 dzie . 8<<1=16
>> Przesuni cie bitów w prawo (Shift Right) Je li operacje maj by wykonywane nie na bitach a na logicznej
>> 00001000 = 00000100 dzie . 8>>2=2 warto ci wyra e :
47
|| oznacza sum (LUB); Po pierwsze:
&& oznacza iloczyn (I);
! oznacza negacj (NIE). C/C++ mo e sam dokonywa konwersji, czyli zmiany typów danych
naogół zgodnie z zasad nadawania zmiennej "mniej pojemnego"
Przykłady: rodzaju typu zmiennej "bardziej pojemnego" rodzaju przed
wykonaniem operacji;
(x==0 || x>5) - x równa si 0 LUB x wi kszy ni 5;
(a>5 && a!=11) - a wi ksze ni 5 I a nie równe 11; Po drugie:
(num>=5 && num!=6 || a>0)
my sami mo emy zmusi C++ do zmiany typu FORSUJ C typ wiadomie
num nie mniejsze ni 5 I num nie równe 6 LUB a dodatnie; w programie.
Wyra enia logiczne sprawdzane instrukcj if MUSZ by uj te w W przykładzie poni ej podaj c w nawiasach dany typ zmiennej
nawiasy okr głe. forsujemy zmian typu int na typ float.
* została umieszczona na pocz tku programu poza funkcj main(), ZREZYGNOWA Z DEKLARACJI FUNKCJI. Dodaj c do programu wiersz:
* zawiera deklaracj zarówno typu funkcji, jak i typów
argumentów. #include <math.h>
Przykład prototypu (funkcja2.cpp): doł czaj cy plik zawieraj cy prototyp funkcji sqrt(), mo esz
napisa program tak:
double FUNKCJA( double X, double Y);
#include <stdio.h>
main() #include <math.h>
{ main()
49
{
Próba wydrukowania zmiennej Argument gdziekolwiek poza wn trzem
double a, b; FUNKCJI() nie uda si i spowoduje komunikat o bł dzie. Oznacza
clrscr(); to, e POZA FUNKCJ zmienna Argument NIE ISTNIEJE. Jest tworzona
printf("Podaj liczbe\n");
scanf("%lf", &a); na stosie jako zmienna automatyczna na wył czny u ytek funkcji,
b = sqrt(a); w której została zadeklarowana i znika po wyj ciu z funkcji.
printf("\n %Lf", (long double) b); Przy takiej organizacji funkcji i programu funkcja otrzymuje
getch(); kopi zmiennej, na niej wykonuje swoje działania, natomiast
zmienna (zmienne) wewn trzna funkcji znika po wyj ciu z funkcji.
return 0;
} Problem przekazania parametrów pomi dzy funkcjami wywołuj cymi
("wy szego rz du" - tu: main) i wywoływanymi (tu: FUNKCJA) mo na
W C++ cz sto przekazuje si parametry do funkcji przy pomocy * instrukcji return (zwrot do programu jednej warto ci) lub
wska ników. Aby prze ledzi co dzieje si wewn trz funkcji wpisz * wska ników.
i uruchom podany ni ej program przykładowy. Najpierw Mo emy przecie funkcji przekaza nie sam zmienn , a wska nik
skonstruujemy sam program a nast pnie zmodyfikujemy go w taki do zmiennej (robili my to ju w przypadku funkcji scanf() -
sposób, aby mógł sobie popodgl da cały proces. Przy pomocy dlatego, e samej zmiennej jeszcze nie było - miała zosta
funkcji printf() ka emy wydrukowa kolejne stany zmiennych, stan dopiero pobrana, ale istniało ju przeznaczone na t now
zmienn - zarezerwowane dla niej miejsce. Mogł zatem istnie
programu i funkcji, a funkcja getch() pozwoli Ci obejrze to wska nik wskazuj cy to miejsce). wska nik nale y oczywi cie
"krok po kroku". Mogłoby si wydawa , e program poni ej zadeklarowa . Nasz program przybrałby zatem now posta .
skonstruowany jest poprawnie... Wska nik do zmiennej nazwiemy *Argument.
[P050.CPP]
WSKA NIKI DO FUNKCJI.
void Wypelniacz(char *BUFOR, char Znak, int Dlugosc);
W C++ mo emy nie tylko podstawi dan w miejsce zmiennej (co
char TAB2D[5][10]; // Tablica 5 X 10 = 50 elementow jest trywialn i oczywist operacj we wszystkich j zykach
char TAB_1D[50]; // Tablica 1 X 50 = 50 elementow programowania), ale mo emy tak e podstawia na miejsce funkcji
int k; stosowanej w programie t funkcj , która w danym momencie jest
nam potrzebna. Aby wskaza funkcj zastosujemy, jak sama nazwa
main() wskazuje - WSKA NIK DO FUNKCJI. Aby unikn deklarowania funkcji
{
clrscr(); standardowych i by w zgodzie z dobrymi manierami nie zapomnimy
Wypelniacz( TAB_1D, 'X', 41); //Wypelnia X-ami o doł czeniu pliku z prototypami. Deklaracj
printf("%s\n\n", TAB_1D);
for (k=0; k<5; k++) Wypelniacz( TAB2D[k], 65+k, 9); double ( *FUNKCJA ) (double);
//ASCII 65 to 'A'; 66 to 'B' itd.
nale y rozumie :
for (k=0; k<5; k++) printf("%s\n", TAB2D[k]); "Przy pomocy wska nika do funkcji *FUNKCJA wolno nam wskaza
getch(); takie funkcje, które
return 0; * pobieraj jeden argument typu double float;
} * zwracaj do programu warto typu double float. "
Dost pne s dla nas zatem wszystkie standardowe funkcje
void Wypelniacz( char *BUFOR, char Znak, int Dlugosc ) arytmetyczne z pliku MATH.H (MATH pochodzi od MATHematics -
{ matematyka.)
int i;
for ( i=0; i<=(Dlugosc-1); i++) *(BUFOR+i) = Znak; [P052.CPP]
*(BUFOR+Dlugosc) = '\0';
} # include <conio.h>
# include <math.h>
Zwró uwag , e: double NASZA( double ); //Deklaracja zwyklej funkcji
* NAZWA TABLICY (tu: TAB_1D i TAB2D) funkcjonuje jako wska nik
PIERWSZEGO ELEMENTU TABLICY. double (*Funkcja)(double ARG); //pointer do funkcji
int argc - liczba całkowita (>=1, bo parametr Nr 1 to nazwa 3 Spróbuj przeprowadzi rzutowanie typu we własnym programie.
samego programu, za po rednictwem której DOS wywołuje funkcj
main). Liczba argumentów - parametrów mo e by zmienna. 4 Przeka warto w programie przykładowym posługuj c si
instrukcj :
UWAGA: J zyk programowania wsadowego BPL przyjmuje nazw return (10*Argument + Argument);
programu za parametr %0 a C++ uznaje j za parametr o numerze 5 Rozszerz zestaw funkcji do wyboru w programie przykładowym.
argv[0], tym niemniej, nawet je li nie ma adnych parametrów
argc = 1.
LEKCJA 16 - ASEMBLER TASM i BASM.
argv - to tablica zawieraj ca wska niky do ła cuchów tekstowych ________________________________________________________________
reprezentowanych w kodzie ASCIIZ - nazw kolejnych paramentrów, z W trakcie tej lekcji:
* dowiesz si , jak ł czy C++ z assemblerem
którymi został wywołany program. * poznasz wewn trzne formaty danych
Pierszy element tej tablicy to nazwa programu. Ostatni element ________________________________________________________________
tej tablicy, o numerze argv - 1 to ostatni niezerowy parametr
wywołania programu. WEWN TRZNY FORMAT DANYCH I WSPÓŁPRACA Z
ASSEMBLEREM.
env - to tak e tablica zawieraj ca wska niki do ła cuchów
znakowych w kodzie ASCIIZ reprezentuj cych parametry rodowiska W zale no ci od wybranej wersji kompilatora C++ zasady
(environment variables). Wska nik o warto ci NUL sygnalizuje współpracy z asemblerem mog si troch ró ni . Generalnie,
koniec tablicy. W Turbo C++ istnieje tak e predefiniowana kompilatory współpracuj z tzw. asemblerami in-line (np. BASM),
zmienna globalna (::), przy pomocy której mo na uzyska dost p lub asemblerami zewn trznymi (stand alone assembler np. MASM,
do rodowiska operacyjnego - environ . TASM). Wstawki w programie napisane w assemblerze powinny zosta
________________________________________________________________
poprzedzone słowem asm (BORLAND/Turbo C++), b d _asm (Microsoft
Przykłady poni ej przedstawiaj sposób wykorzystania parametrów
wej ciowych programu.
52
C++). Przy kompilacji nale y zatem stosownie do wybranego MOV DX, OFFSET NAPIS
kompilatora przestrzega specyficznych zasad współpracy. Np. dla MOV AH, 9
INT 21H ;Drukowanie
BORLAND/Turbo C++ mo na stosowa do kompilacji BCC.EXE/TCC.EXE KONIEC:
przy zachowaniu warunku, e TASM.EXE jest dost pny na dysku w MOV AH, 4CH
bie cym katalogu. INT 21H ;Zako czenie programu
END START
Typowymi sposobami wykorzystania assemblera z poziomu C++ s :
Inne typy danych mo emy stosowa podobnie. Wygodn taktyk jest
* umieszczenie ci gu instrukcji assemblera bezpo rednio w deklarowanie danych w tej cz ci programu, która została
ródłowym tek cie programu napisanym w j zyku C/C++, napisana w C++, aby inne fragmenty programu mogły si do tych
* doł czeniu do programu zewn trznych modułów (np. funkcji) danych odwoływa . Mo emy we wstawce asemblerowskiej odwoływa
napisanych w assemblerze. si do tych danych w taki sposób, jakgdyby zostały zadeklarowane
W C++ w tek cie ródłowym programu blok napisany w asemblerze przy u yciu dyrektyw DB, b d DW.
powinien zosta poprzedzony słowem kluczowym asm (lub _asm):
WEWN TRZNE FORMATY DANYCH W C++.
# pragma inline
LICZBY CAŁKOWITE typów char, short int i long int.
void main()
{ Liczba całkowita typu short int stanowi 16-bitowe słowo i mo e
asm mov dl, 81 zosta zastosowana np. w taki sposób:
asm mov ah, 2
asm int 33 [P056.CPP]
}
#pragma inline
Program b dzie drukował na ekranie liter "Q" (ASCII 81). void main()
{
JAK POSŁUGIWA SI DANYMI W ASEMBLERZE. char *napis = "\nRazem warzyw: $";
int marchewki = 2, pietruszki = 5;
Napiszemy w asemblerze program drukuj cy na ekranie napis "tekst asm {
MOV DX, napis
- test". Rozpczynamy od zadeklarowania ła cucha znaków: MOV AH, 9
INT 33
void main() MOV DX, marchewki
{ ADD DX, pietruszki
char *NAPIS = "tekst - test$"; /* $ - ozn. koniec */ ADD DX, '0'
MOV AH, 2
Umie cili my w pami ci ła cuch, b d cy w istocie tablic INT 33
składaj c si z elementów typu char. Wska nik do ła cucha mo e }
zosta zast piony nazw -identyfikatorem tablicy. Zwró uwag , e }
po ła cuchu znakowym dodali my znak '$'. Dzi ki temu mo emy Zdefiniowali my dwie liczby całkowite i ła cuch znaków - napis.
skorzysta z DOS'owskiej funkcji nr 9 (string-printing DOS Poniewa obie zmienne (ła cuch znków jest stał ) maj długo
service 9). Mo emy utworzy kod w asemblerze: jednego słowa maszynowego, to efekt jest taki sam, jakgdyby
zmienne zostały zadeklarowane przy pomocy dyrektywy asemblera DW
asm mov dx, NAPIS
asm mov ah, 9 (define word). Mo emy pobra warto zmiennej marchewki do
asm int 33 rejestru instrukcj
Cały program b dzie wygl dał tak: MOV DX, marchewki ;marchewki -> DX
starsze słowo z młodszym słowem. Liczba 12345678(hex) zostanie Nast pi natomiast przeniesienie (carry) do dziewi tego (nie
zapisana w pami ci komputera IBM PC jako 78 56 34 12. zawsze istniej cego sprz towo bitu).
Gdy inicjujemy w programie zmienn Wyst pienie przeniesienia powoduje ustawienie flagi CARRY w
rejestrze FLAGS. Je li zignorujemy flag i b dziemy bra pod
long int x = 2; uwag tylko te osiem bitów w rejestrze, oka e si , e
otrzymali my wynik 0000 0000. Krótko mówi c FF = (-1), poniewa
zostaje ona umieszczona w pami ci tak: 02 00 00 00 (hex). FF + 1 = 0.
Młodsze słowo (02 00) jest umieszczone jako pierwsze. To wła nie
Aby odwróci wszystkie bity bajtu, b d słowa mo emy w
słowo zawiera interesuj c nas informacj , mo emy wczyta to asemblerze zastosowa instrukcj NOT. Je li zawarto rejestru
słowo do rejestru rozkazem AX wynosiła np. 0000 1111 0101 0101 (hex 0F55), to instrukcja
NOT AX zmieni j na 1111 0000 1010 1010 (hex F0AA). Dokładnie
MOV DX, X tak samo działa operator bitowy ~_AX w C/C++. W zestawie
rozkazów mikroprocesorów rodziny Intel 80x86 jest tak e
Je li b dzie nam potrzebna druga połówka zmiennej - starsze instrukcja NEG, powoduj ca zamian znaku liczby (dokonuj c
słowo (umieszczone w pami ci jako nast pne), mo emy zastosowa konwersji liczby na kod komplementarny). Instrukcja NEG robi to
pointer (czyli poda adres nast pnego słowa pami ci). samo, co NOT, ale po odwróceniu bitów dodaje jeszcze jedynk .
Je li rejestr BX zawierał 0000 0000 0000 0001 (hex 0001), to po
[P058.CPP] operacji NEG AX zawarto rejestru wyniesie 1111 1111 1111 1111
(hex FFFF).
# pragma inline
void main() Zastosujmy praktycznie uzupełnienia dwójkowe przy współdziałaniu
{
unsigned long marchewki = 2, pietruszki = 5; asemblera z C++:
const char *napis = "\nRazem warzyw: $";
asm [P059.CPP]
{
MOV DX, napis #pragma inline
MOV AH, 9 void main()
INT 33 {
MOV DX, marchewki const char *napis = "\nRazem warzyw: $";
ADD DX, pietruszki int marchewki = -2, pietruszki = 5;
ADD DX, '0' asm {
MOV AH, 2 MOV DX, napis
INT 33 MOV AH, 9
} INT 33
} MOV DX, marchewki
NEG DX
W przypadku liczb całkowitych ujemnych C++ stosuje zapis w ADD DX, pietruszki
kodzie komplementarnym. Aby móc manipulowa takimi danymi ka dy ADD DX, '0'
szanuj cy si komputer powinien mie mo liwo stosowania liczb MOV AH, 2
ujemnych. INT 33
}
Najstarszy bit w słowie, b d bajcie (pierwszy z lewej) mo e }
spełnia rol bitu znakowego. O tym, czy liczba jest ze znakiem,
Dzi ki zamianie (-2) na 2 przy pomocy instrukcji NEG DX
czy te bez decyduje wył cznie to, czy zwracamy uwag na ten otrzymamy wynik, jak poprzednio równy 7.
bit. W liczbach bez znaku, oboj tnie, czy o długo ci słowa, czy
bajtu, ten bit równie jest (i był tam zawsze!), ale Przypomnijmy prezentacj działania operatorów bitowych C++.
traktowali my go, jako najstarszy bit nie przydaj c mu poza tym Wykorzystaj program przykładowy do przegl du bitowej
adnego szczególnego znaczenia. Aby liczba stała si liczb ze reprezentacji liczb typu int (ze znakiem i bez).
znakiem - to my musimy zacz j traktowa jako liczb ze
znakiem, czyli zacz zwraca uwag na ten pierwszy bit. [P060.CPP]
Pierwszy, najstarszy bit liczby ustawiony do stanu 1 b dzie
54
/* Program prezentuje format liczb i operatory bitowe */ char *TEKST = "\ntekst - test$";
//*TEKST to znany funkcji zewn trzny wska nik Return n oznacza liczb bajtów zajmowanych ł cznie przez
wszystkie odło one na stos parametry.
#pragma inline
W C++ parametry s odkładane na stos w odwróconej kolejno ci.
55
Je li chcemy, by parametry zostały odło one na stos kolejno, dwubajtowe słowo maszynowe.
powinni my zadeklarowa funkcj jako "funkcj z Pascalowskimi
manierami" - np.: # include <....
....
pascal void nazwa_funkcji(void); # pragma inline
void main()
Dodatkowo, w C++ argumenty s przekazywane poprzez swoj {
warto , a nie przez wskazanie adresu parametru, jak ma to float liczba = 3.5;
miejsce np. w BASICU. Istnieje tu kilka wyj tków przy ....
przekazywaniu do funkcji struktur i tablic - bardziej
szczegółowo zajmiemy si tym w dalszej cz ci ksi ki. Je eli zajrzymy do pami ci naszego PC, oka e si , e liczba 3.5
została tam "zaszyfrowana" jako 00 00 60 40. Dlaczego? Format
Rozbudujemy nasz przykładowy program w taki sposób, by do liczb zmiennoprzecinkowych jest znacznie bardziej skomplikowany.
funkcji były przekazywane dwa parametry - litery 'A' i 'B'
przeznaczone do wydrukowania na ekranie przez funkcj : Liczba dziesi tna w rodzaju 123.4 to
void wyswietl(char x, char y) //Definicja (implementacja) 1*21 + 1*20 + 1*2-1 = 2 + 1 + 1/2 {* !UWAGA SKLAD: potegi *}
{
.... czyli 0000 0000 0000 0011.1000 0000 0000 0000
Parametry zostan odło one na stos: Kropka oznacza przecinek oddzielaj cy cz całkowit od cz ci
ułamkowaj - "przecinek dwójkowy" (a nie dziesi tny!). Ka d
PUSH 'B' liczb dziesi tna mo na zamieni na liczb dwójkow .
PUSH 'A' Przykładowodziei tne 7.75 mo na zamieni na
Ka dy parametr (mimo typu char) zajmie na stosie pełne słowo. 4 + 2 + 1 + 1/2 + 1/4 = 0000 0000 0000 0111.1100 (dwójkowo)
C++ nie potrafi niestety układa na stosie bajt po bajcie.
Funkcja wyswietl() musi uzyska dost p do przekazanych jej Pozostaje jednak pewien problem. Komputer nie ma mo liwo ci
argumentówów. Odwołamy si do zmiennych C++ w taki sposób, jak zaznaczenia przecinka, dlatego te przecinek musi by ustawiany
robiłaby to ka da inna funkcja w C++: zawsze w tej samej pozycji - blisko pocz tku liczby.
LEKCJA 17: TROCH SZCZEGÓLÓW TECHNICZNYCH. A teraz znak liczby. Pierwszy bit ka dej liczby
________________________________________________________________ zmiennoprzecinkowej okre la znak liczby (ang. sign bit). Liczby
W trakcie tej lekcji dowiesz si wi cej o szczegółach działania zmiennoprzecinkowe nie s przechowywane w postaci dwójkowych
komputera widzianych z poziomu assemblera. uzupełnie . Je li pierwszy bit - bit znaku równy jest 1 - liczba
________________________________________________________________
jest ujemna. natomiast je eli 0, liczba jest dodatnia. Jest to
LICZBY ZMIENNOPRZECINKOWE TYPU float. jedyna ró nica pomi dzy dodatnimi a ujemnymi liczbami
zmiennoprzecinkowymi. Nasza liczba 3.5 = 11.1 zostanie
To, e C++ przy wywołaniu funkcji jest "przyzwyczajony" do zakodowana jako:
odkładania argumentów na stos zawsze po dwa bajty mo e nam
sprawi troch kłopotów, gdy zechcemy zastosowa argument typu znak liczby -0
float, double, b d long - znacznie przekraczaj cy długo ci wykładnik pot gi - 1000 0000
56
cyfry znacz ce liczby - 110000000.... double AX = Adres (je li far to DX:AX)
struct AX = Adres (je li far to DX:AX)
Poniewa wiemy, e mamy do dyspozycji dla liczb float 4 bajty near pointer AX
(mo esz to sprawdzi sizeof(float x=3.5)), uzupełnijmy brakuj ce far pointer DX:AX
________________________________________________________________
do 32 bity zerami:
3.5 = 0100 0000 0110 0000 0000 0000 0000 0000 = 40 60 00 00 Zale nie od typu warto ci zwracanej przez funkcj (okre lonej w
prototypie funkcji), C++ odczytuje zawarto odpowiedniego
zapis 40600000 to oczywi cie szesnastkowa posta naszej liczby. rejestru: AL, AX lub DX:AX. Je li funkcja ma np. zwróci warto
Je li teraz we miemy pod uwag , e nasz PC zamieni miejscami
starsze słowo z młodszym 00 00 40 60 a nast pnie w obr bie o długo ci jednego bajtu, to przed wyj ciem z funkcji nale y j
ka dego słowa dodatkowo starszy bit z młodszym, to zrozumiemy, "zostwi " w rejestrze AL. Je li wywołuj c funkcj C++ oczekuje
dlaczego nasza liczba "siedziała" w pami ci w zaszyfrowanej zwrotu warto ci jednobajtowej, to po powrocie z funkcji
postaci 00 00 60 40. automatycznie pobierze bajt z rejestru AL. Krótkie warto ci
(typu short int) s "pozostawiane" przez funkcj w AX, a długie
Rozpatrzmy szkielet programu wykorzystuj cego funkcj z "długim" w parze rejestrów: DX - starsze, AX - młodsze słowo.
argumentem. Aby zapanowa nad zapisem liczby zmiennoprzecinkowej Zastosujmy to w programie. Funkcja b dzie odejmowa dwie liczby
całkowite. Pobierze dwa argumenty typu int, wykona odejmowanie i
do pami ci naszego PC mo emy na poziomie assemblera post pi np.
zwróci wynik typu int (return (_AX)). Dla modelu pami ci small
tak: b dzie to wygl da tak:
[P064.CPP]
# include <.....
# pragma inline # include <iostream.h>
void funkcja(long int) //Prototyp funkcji # pragma inline
main() int funkcja(int, int); //Prototyp funkcji
{
long liczba = 0xABCDCDEF; //Deklaracja argumentu void main()
..... {
funkcja(liczba); //Wywołanie w programie cout << "\nWynik 7 - 8 = " << funkcja(7, 8);
.... }
}
int funkcja(int x, int y) //Implementacja funkcji
void funkcja(long int x) //Implementacja funkcji {
{ ..... } // x - argument formalny asm {
MOV AX, x
Argument przekazywany funkcji() jest zmienn 4 - bajtow typu SUB AX, y
long int. Mo emy j zamieni na dwa słowa, zanim przeka emy j }
do wykorzystania w asemblerowskiej cz ci programu. return (_AX); //Zwró zawarto rejestru AX
}
funkcja(long int x)
{ Zwró uwag , e po return(_AX); stawiamy rednik, natomiast po
int x1starsze, x2mlodsze; //Wewn trzne zmienne pomocnicze instrukcjach assemblera nie:
x2mlodsze = (int) x;
x >> 16; asm MOV AX, DX
x1starsze = (int) x;
_DX = x1starsze; chyba, e chcemy umie ci kilka instrukcji assemblera w jednej
_BX = x2mlodsze; linii (patrz ni ej).
asm {
...... //Tu funkcja ju mo e działa C++ i assembler s równoprawnymi partnerami. C++ mo e odwoływa
si do zmiennych i funkcji assemblera, je li zostały
Forsuj c konwersj typu na (int), spowodujemy, e młodsze słowo zadeklarowane, jako publiczne (public) oraz zewn trzne
zostanie przypisane zwyczajnej krótkiej zmiennej x2mlodsze. (EXTeRNal) i vice versa. C++ oczekuje, e zewn trzne
Nast pnie zawarto długiej zmiennej zostanie przesuni ta o 16 identyfikatory b d si rozpoczyna od znaku podkre lenia "_".
bitów w prawo (starsze słowo zostanie przesuni te na miejsce Je li w programie pisanym w BORLAND C++ zastosujemy zewn trzne
młodszego). Powtórzenie operacji przypisania spowoduje zmienne i funkcje, C++ sam automatycznie doda do identyfikatorów
przypisanie zmiennej x1starsze starszej połówki słowa. Od tej
chwili mo emy odwoła si do tych zmiennych w naszym fragmencie znak podkre lenia. Turbo Assembler nie robi tego automatycznie i
napisanym w asemblerze. Post pujemy tak, by to C++ martwił si o
musimy zadba o to "r cznie". Przykładowo, współpraca pomi dzy
szczegóły techniczne i sam manipulował stosem i jednocze nie programem P .CPP i modułem MODUL.ASM b dzie przebiega
pilnował poprawno ci konwersji danych. poprawnie:
A teraz kilka słów o tym, co si dzieje, gdy funkcja zapragnie extern int UstawFlage(void); //Prototyp funkcji
zwróci jak warto do programu. int Flaga;
void main()
Wykorzystanie przez funkcje rejestrów do zwrotu warto ci. {
________________________________________________________________ UstawFlage();
}
Typ warto ci Funkcja u ywa rejestru (lub pary)
________________________________________________________________ [MODUL.ASM]
signed char / unsigned char AL
short AX .MODEL SMALL
int AX .DATA
enum AX EXTRN _Flaga:WORD
long para DX:AX (starsze słowo DX, młodsze .CODE
AX) PUBLIC _UstawFlage
float AX = Adres (je li far to DX:AX) _UstawFlage PROC
57
CMP [_Flaga], 0
JNZ SKASUJ_Flage Posługuj c si systemowym debuggerem DEBUG mo esz łatwo
MOV [_Flaga], 1 przejrze tablic wektorów przerywa własnego komputera. Je li
JMP SHORT KONIEC wydasz rozkaz:
SKASUJ_Flage: MOV [_Flaga], 0
KONIEC: C:\DOS\DEBUG
RET -D 0:0
_UstawFlage ENDP
END zobaczysz zawarto pierwszych 32 wektorów int #0...int#31,
czyli pierwsze 128 bajtów pami ci:
Kompilacja mo e przebiega oddzielnie wg schematu:
-d 0:0
PROGRAM.CPP --> PROGRAM.OBJ
MODUL.ASM --> MODUL.OBJ 0000:0000 FB 91 32 00 F4 06 70 00-78 F8 00 F0 F4 06 70 00
TLINK PROGRAM.OBJ MODUL.OBJ --> PROGRAM.EXE 0000:0010 F4 06 70 00 54 FF 00 F0-53 FF 00 F0 53 FF 00 F0
0000:0020 A5 FE 00 F0 87 E9 00 F0-23 FF 00 F0 23 FF 00 F0
Lub mo emy powierzy t prac kompilatorowi, który sam wywoła 0000:0030 23 FF 00 F0 CE 02 00 C8-57 EF 00 F0 F4 06 70 00
TASM i TLINK: 0000:0040 D1 0C BD 1B 4D F8 00 F0-41 F8 00 F0 74 07 70 00
0000:0050 39 E7 00 F0 4A 08 70 00-2E E8 00 F0 D2 EF 00 F0
TCC PROGRAM.CPP MODUL.ASM 0000:0060 00 00 FF FF FB 07 70 00-5D 0C 00 CA 9F 01 BD 1B
0000:0070 53 FF 00 F0 A0 7C 00 C0-22 05 00 00 2F 58 00 C0
W BORLAND C++ 3.1 mamy do dyspozycji zintegrowany assembler
(ang. in-line) - BASM. Ma on jednak w stosunku do Po zdeszyfrowaniu oka e si , e pierwszy wektor (przerywanie 0)
"wolnostoj cego" Turbo Assemblera pewne ograniczenia: wskazuje na adres startowy: 0032:91FB (adres absolutny 0951B).
Generalnie mo liwe s cztery sytuacje. Wektor mo e wskazywa :
* ma zaw ony w stosunku do TASM zestaw dyrektyw (tylko DB, DD,
DW, EXTRN); * adres startowy procedur ROM-BIOS: blok F - Fxxx:xxxx,
* nie pozwala na stosowanie składni typowej dla trybu "Ideal * adres funkcji DOS,
mode"; * adres funkcji działaj cego wła nie debuggera (DEBUG przejmuje
* nie pozwala na zastosowanie makra; obsług niektórych przerywa ), lub innego programu rezyduj cego
* nie pozwala stosowa instrukcji charakterystycznych dla 386 w pami ci - np. NC.EXE,
ani 486. * wektor mo e by pusty - 00 00:00 00 je li dane przerywanie nie
Mo esz stosowa kilka rozkazów assemblera w jednej linii, ale jest obsługiwane.
powiniene rozdziela je wewn trz linii rednikami:
Je li zechcesz sprawdzi , jak obsługiwane jest dane przerywanie
asm { mo esz znów zastosowa debugger, wydaj c mu rozkaz
POP AX; POP DX; POP DS zdezasamblowania zawarto ci pami ci pocz wszy od wskazanego
IRET adresu:
}
-u 32:91FB
Komentarz we wstawce assemblerowskiej musi zosta poprzedzony
typowym dla C - /* (sam rednik, jak w TASM jest 0032:91FB BE6B47 MOV SI,476B
niedopuszczalny): 0032:91FE 2E CS:
0032:91FF 8B1E7E47 MOV BX,[477E]
asm { 0032:9203 2E CS:
MOV DX, 1 ;TAK NIE MO NA W BASM ! 0032:9204 8E16D73D MOV SS,[3DD7]
... 0032:9208 BCA007 MOV SP,07A0
asm { 0032:920B ˙˙˙˙˙˙˙˙˙˙˙E80200 ˙˙˙˙˙˙˙˙˙˙CALL ˙˙˙˙˙˙˙˙˙˙9210
ADD AX, BX; /* Taki komentarz mo e by */
0032:920E EBDA JMP 91EA
[???] KŁOPOTY Z REJESTRAMI ? 0032:9210 ˙˙˙˙˙˙˙˙˙˙˙16 ˙˙˙˙˙˙˙˙˙˙˙PUSH ˙˙˙˙˙˙˙˙˙˙˙SS
________________________________________________________________
Je li zastosujesz rejestry DI i SI we wstawce assemblerowaj, 0032:9211 07 POP ES
kompilator C++ nie b dzie miał gdzie umie ci zmiennych klasy 0032:9212 ˙˙˙˙˙˙˙˙˙˙˙16 ˙˙˙˙˙˙˙˙˙˙˙PUSH ˙˙˙˙˙˙˙˙˙˙˙SS
register z programu głónego. Zastanów si - co si bardziej
opłaca. 0032:9213 1F POP DS
________________________________________________________________ 0032:9214 C606940308 MOV BYTE PTR [0394],08
0032:9219 C606920316 MOV BYTE PTR [0392],16
O WEKTORACH PRZERYWA DOS
Z poziomu assemblera do wektora i odpowiednio do funkcji
Mikroprocesory Intel 80X86 rezerwuj w pami ci naszych PC obsługuj cej przerywanie mo esz odwoła si instrukcj INT
pocz tkowe 1024 Bajty (adresy fizyczne 00000...00400 hex) na 256 numer.
wektorów przerywa (ka dy wektor składa si z dwu słów i mo e Zmienna numer mo e tu przyjmowa warto ci od 00 do FF. Je li
by traktowany jako DW, b d far pointer). Nast pne 256 bajtów wydasz taki rozkaz, komputer zapisze na stos ( eby sobie nie
(00400...00500 hex) zajmuje BIOS, a kolejne 256 (00500...00600 zapomnie ) zawarto rejestrów CS - bie . segment rozkazu, IP -
hex) wykorzystuje DOS i Basic. bie cy offset rozkazu i FLAGS. Nast pnie wykona daleki (far
jump) skok do adresu wskazanego przez wektor.
Wektor to w samej rzeczy pełny adres pocz tku procedury
obsługuj cej przerywanie o danym numerze Je li jednak cz przerywa jest "niewykorzystana", lub w Twoim
Adres pami ci: 0000:0000 [OFFSET Wekt. int 0] Aby Twoja funkcja mogła sta si "handlerem" przerywania, mo esz
0000:0002 [SEGMENT int 0]
0000:0004 [OFFSET Wekt. int 1] zadeklarowa j tak:
0000:0006 [SEGMENT int 1]
0000:0008 [OFFSET int 2] void interrupt MojaFunkcja(bp, di, si, ds .....)
.... ....
Procesory 80X86 zamieniaj jeszcze dodatkowo starszy bajt z Do funkcji klasy interrupt przekazywane s jako argumenty
młodszym. rejestry, nie musisz zatem stosowa pseudozmiennych _AX, _FLAGS
58
itp.. Je li zadeklarujesz funkcj jako handler przy pomocy słowa {
Instaluj(Piszczek, 10);
"interrupt", funkcja automatycznie zapami tuje stan rejestrów: Start(5, 10);
AX, BX, CX, DX, SI, DI, BP, ES i DS. }
Po powrocie z funkcji rejestry zostan automatycznie odtworzone.
Nale y do dobrych manier odtworzy po wykorzystaniu oryginaln
Przykładem funkcji obsługuj cej przerywanie mo e by piszczek() zawarto wektora przerywania, który "unowocze nili my". W
posługuj cy si wbudowanym gło niczkiem i portem: bibliotece BORLAND C++ masz do dyspozycji m. in. funkcje
setvect() (ustaw wektor przerywania) i potrzebuje dwu Dost p do starszej połowy rejestru mo na uzyska np. poprzez
argumentów: przesuwanie (rotation):
void Start(unsigned char licznik, int numer_wektora) BSF, BSR, BTR, BTS, LFS, LGS, MOVZX, SETxx,
{ BT, BTC, CDQ, CWDE, LSS, MOVSX, SHLD i SHRD.
_AH = licznik;
geninterrupt(numer_wektora); //generuj przerywanie Przy pomocji instrukcji MOV w trybie uprzywilejowanym (tzw.
} most-privileged level 0 - tylko w trybie .386P) mo esz dodatkowo
Nasz główny program b dzie zatem wygl da tak: uzyska dost p do specjalnych rejestrów mikroprocesora 80386.
String, czyli ła cuch - to gupa znaków "pisarskich" (liter, cyfr char *p = "Jakis tam napis";
i znaków specjalnych typu ?, !, _ itp.). Poniewa C++ nie ma Rzu my okiem na kilka gotowych funkcji, które do manipulowania
odzielnego typu danych "string" - ła cuchy znaków to tablice tekstami oferuje C++.
zło one z pojedynczych znaków (typowe elementy typu char).
Technik obiektow mo na utworzy klas - nowy typ danych Ł CZENIE TEKSTÓW.
"string". W bibliotekach Microsoft C++ istnieje predefiniowana
klasa CString, ale zanim przejdziemy do programowania [S] String Concatenation - ł czenie ła cuchów tekstowych.
obiektowego i zdarzeniowego - rozwa my manipulowanie tekstami w Zlepek/skrót. Słowo strcat w j zyku C++ znaczy sklej.
sposób najprostszy.
W praktycznych programach zapewne cz sto pojawi si dwa lub
Maksymaln mo liw długo napisu nale y poda wtedy, gdy w wi cej tekstów, które trzeba b dzie poł czy w jeden napis.
programie deklaruje si zmienn tekstow : Wyobra my sobie, e imi i nazwisko u ytkownika mamy zapisane
jako dwa oddzielne ła cuchy tekstowe. Aby poł czy te dwa teksty
char tekst1[40];
w jeden trzeba przeprowadzi tzw. sklejanie (ang. concatenation)
Jest to poprawna deklaracja zmiennej tekstowej o nazwie
(identyfikator) tekst1. Maksymalna długo tekstu, który mo na tekstów. W j zyku C++ mamy w tym celu do dyspozycji specjaln
umie ci w tej zmiennej tekstowej to - 40 znaków (liter, cyfr, funkcj :
itp.). A je li chc zastosowa tylko pojedynczy znak zamiast
całego napisu? To proste: strcat() - STRing conCATenation - sklejanie ła cuchów.
char napis[1]; Aby poł czy dwa ła cuchy tekstowe napis1 i napis2 w jeden
nale y zastosowa t funkcj w taki sposób:
Skoro długo ła cucha wynosi 1, to przecie nie jest aden
ła cuch! Informacja o długo ci (size - wielko ) wpisywana w strcat(napis1, napis2);
nawiasy jest zb dna. Uproszczona wersja utworzenia zmiennej
jednoznakowej i nadania zmiennej nazwy wygl da w tak: Funkcja strcat() zadziała w taki sposób, e ła cuch znaków
napis2 zostanie doł czony do ko ca ła cucha napis1. Po
char znak; zako czeniu działania funkcji zmienna napis1 zawiera "swój
własny" napis i doł czony na ko cu napis zawarty uprzednio w
Nie jest to ju jednak deklaracja zmiennej ła cuchowej - lecz zmiennej napis2.
deklaracja zmiennej znakowej. Ła cuch znaków (string) to grupa
znaków (dokł. tablica znakowa) zako czona zwykle przez tzw. Program poni ej przedstawia praktyczny przykład zastosowania
"wartownika" - znak NULL (zero). A pojedynczy znak to tylko funkcji strcat().
pojedynczy znak. Nie ma tu miejsca (i sensu) dodawanie po
pojedynczym znaku "wartownika" ko ca tekstu - zera. [P066.CPP]
60
clrscr(); starych, zb dnych danych.
cout << "Podaj imie: ";
cin >> imie; Mo liwo sprawdzenia, jak długo ma ła cuch tekstowy mo e si
cout << "Podaj nazwisko: "; to przyda np. do rozmieszczenia napisów na ekranie. Dla
cin >> nazwisko; przykładu, pozycja na ekranie, od której rozpocznie si
wy wietlanie napisu zale y od długo ci tekstu, który został
strcat(imie, " "); wy wietlony wcze niej. Do okre lania długo ci tekstu masz w C++
strcat(imie, nazwisko); do dyspozycji gotow funkcj :
cout << "\nNazywasz sie: " << imie << '\n'; strlen() - STRing LENgth - długo ła cucha znakowego.
cout << "Naci nij dowolny klawisz";
getch(); Funkcj strlen() stosuje si w nast puj cy sposób:
return 0;
} unsigned int dlugosc;
char tekst[...];
...
Program zapyta najpierw o imi a nast pnie o nazwisko. Po dlugosc = strlen(tekst);
wpisaniu przez Ciebie odpowiedzi program doda do siebie oba
teksty i wypisze na ekranie Twoje imi i nazwisko w cało ci. Funkcja ma jeden argument - napis, którego długo nale y
Interesuj xe w programie jest poł czenie przy pomocy funkcji C++ okre li (tu: zmienna nazywa si tekst). Funkcja strlen() w
wyniku swojego działania ZWRACA długo ła cucha tekstowego jako
strcat() dwu ła cuchów tekstowych w jeden ła cuch z dodaniem
spacji rozdzielaj cej ła cuchy znaków. Najistotniejszy fragment liczb całkowit bez znaku (nieujemn ). Liczba zwrócona jako
programu wraz z komentarzem - poni ej. wynik przez funkcj strlen() mo e zosta u yta w dowolny sposób
- jak ka da inna warto numeryczna.
strcat(imie, " "); <-- dodaj do ko ca tekstu spacj
strcat(imie, nazwisko); <-- po doł czonej spacji dodaj Funkcja strlen() nie podaje w odpowiedzi na wywołanie (m drze
drugi tekst - nazwisko nazywa si to "zwraca do programu warto ") długo ci ła cucha
tekstowego, która została zadeklarowana (maksymalnej
Poniewa prototyp funkcji strcat() znajduje si w pliku STRING.H teoretycznej), lecz FAKTYCZN DŁUGO tekstu. Je li, dla
przykładu, zadeklarujemy zmienn tekstow tak:
- nale y doł czy ten plik nagłówkowy dyrektyw #include.
char string1[30] = "Lubie C++ ";
DŁUGO ŁA CUCHA TEKSTOWEGO.
zadeklarowana maksymalna długo ła cucha znakowego wynosi 30,
Ka dy tekst ma swoj długo : liczb znaków, z których si natomiast faktyczna długo ła cucha znakowego wynosi 10 znaków.
składa. Dla przykładu ła cuch znaków:
Je li wywołamy strlen() i ka emy jej okre li długo ła cucha
"Przychodzi katecheta do lekarza i płacze, a lekarz na to: Bóg znakowego string1:
dał - Bóg wzi ł..."
unsigned int dlugosc = strlen(string1);
ma dla długo 71, poniewa składa si z 71 znaków (odst p -
spacja to te znak). Ła cuch znaków funkcja przypisze zmiennej dlugosc warto 10 a nie 30.
"Ile diabłów mie ci si w łebku od szpilki?" Je li wpisałe poprzedni program program przykładowy do okienka
edycyjnego - wystarczy doda dwa nowe wiersze.
ma długo 42. Teoretycznie długo ła cuchów znakowych mo e
wynosi od 0 do niesko czono ci, ale w Borland/Turbo C++ [P067.CPP]
wyst puje ograniczenie: ła cuch znaków mo e mie długo zawart
#include <conio.h>
w przedziale od 0 do 65536 znaków. Taki np. ła cuch znaków jest #include <iostream.h>
całkiem do przyj cia: #include <string.h>
"Nie wa ne, czy Polska b dzie bogata, czy biedna - wa ne, eby main()
była katolicka (czyli nasza), bo nasze b d wtedy pieni dze, {
urz dy i nasza władza. Lepiej by pół-Bogiem w ród n dzarzy char imie[50], nazwisko[20];
(oczywi cie za ich pieni dze, z ich podatków), ni zarabia na int dlugosc;
chleb własn prac ."
clrscr();
[S] Null string - Ła cuch zerowy. cout << "Podaj imie: ";
________________________________________________________________ cin >> imie;
cout << "Podaj nazwisko: ";
Ła cuch zerowy (dokładniej: ła cuch tekstowy o zerowej długo ci) cin >> nazwisko;
strcat(imie, " ");
to taki ła cuch, który zawiera 0 (zero) znaków. Jak to mo liwe, strcat(imie, nazwisko);
by ła cuch tekstowy zawierał zero znaków? W C++ ła cuchy znaków cout << "\nNazywasz sie: " << imie << '\n';
zawieraj na ko cu znak '\0' (zero) jako "wartownika" ko ca dlugosc = strlen(imie);
tekstu. Je li pierwszy element tablicy znakowej b dzie zerem - cout<<"Imie i nazwisko sklada sie z: "<<dlugosc<<"znakow\n";
powstanie wła nie ła cuch znakowy o zerowej długo ci. Mo na to cout << "Nacisnij dowolny klawisz";
zrobi np. tak: getch();
return 0;
char napis[0] = 0; }
char *p = "";
char napis[50] = ""; W programie z Listingu 5.2 nie musisz stosowa dodatkowej
________________________________________________________________ zmiennej dlugosc. Taki sam efekt uzyskasz pisz c zamiast dwu
wierszy jeden:
Kiedy C++ wyznacza długo ła cucha znaków - zlicza kolejne cout << "Wszystkich znakow bylo: " << strlen(imie) << '\n';
znaki, a dojdzie do zera. W przykładzie ju pierwszy znak jest
zerem, wi c C++ uzna, e długo takiego ła cucha wynosi zero. POBIERANIE I WYSZUKIWANIE WYCINKA TEKSTU - substring.
Czasem w praktyce programowania zainicjowanie takiego pustego
ła cucha pozwala mie pewno , e tablica nie zawiera jakich Podobnie łatwo do ł czenia ła cuchów mo esz dokona podziału
61
wi kszych tekstów na mniejsze fragmenty. "Du e" pierwone
ła cuchy nazywaj si "string", a te mniejsze fragmenty - clrscr();
"substring". Do podziału ła cuchów na "podła cuchy" j zyk C++ cout << "Wpisz jakis tekst: ";
dysponuje specjalnymi funkcjami: gets(napis1);
Rozwa my program przykładowy. Po uruchomieniu program poprosi o funkcja gets() pozwala wczyta wiersz tekstu zawieraj cy dowolne
wpisanie ła cucha tekstowego. Wpisz dowolny tekst. Tekst
powinien zawiera wi cej ni 3 znaki. Po pobraniu znaki uznaj c za koniec znak CRLF (powrót karetki, zmiana
wyj ciowego/ ródłowego tekstu od u ytkownika, program pobierze z wiersza) generowany po naci ni ciu [Entera]. Przeciwn ,
symetryczn funkcj do gets() jest funkcja puts() (ang. PUT
tego tekstu kilka mniejszych ła cuchów tekstowych typu String - wyprowad wiersz tekstu). Prototypy funkcji gets() i
"substring" i wy wietli je na ekranie. puts() znajduj si w pliku nagłówkowym STDIO.H. Dlatego ten
plik nagłówkowy został doł czony na pocz tku dyrektyw #include.
[P068.CPP]
Aby komputer zarezerwował miejsce w pami ci dla wska nika, DU E I MAŁE LITERY.
trzeba go o to "poprosi " na pocz tku programu, deklaruj c, e w
Litery mog by małe i du e. Du e litery nazywaj si
programie zamierzamy posługiwa si wska nikiem. Deklaracja "capitals". Od słowa CAPitalS pochodzi skrót na klawiszu [Caps
wska nika do zmiennej tekstowej wygl da tak: Lock]. Innym, u ywanym do okre lenia tego samego słowem jest
"upper case" (du e litery) lub "lower case" (małe litery).
char *wskaznik; Czasami pojawia si potrzeba zaminy du ych liter na małe, b d
odwrotnie. W C++ słu tego celu funkcje:
Przykładowy program pni ej demonstruje sposób zadeklarowania
wska nika i wyszukiwanie tekstu. Program nie oczekuje adnej strupr() - STRing to UPpeR case - zamie litery wła cuchu
informacji wej ciowej od u ytkownika. Uruchom program i tekstowym na du e.
przeanalizuj wydruk na ekranie porównuj c go z tekstem programu. strlwr() - STRing to LoWeR case - zamie litery w ła cuchu na
małe.
cout << "Tekst 'Alfons' wystapil po raz pierwszy:\n"; cout << "\nNormalnie: " << string1 << '\n';
cout << " " << pointer << '\n'; cout << "TYLKO DUZE: " << strupr(string1) << '\n';
cout << "tylko male: " << strlwr(string1) << '\n';
pointer = strstr(ptr, "Jasiek"); cout << "\n\n...Nacisnij klawisz...";
cout << "Tekst 'Jasiek' wystapil po raz pierwszy:\n"; getch();
cout << " " << pointer << '\n'; return 0;
}
pointer = strstr(pointer, "As");
cout << "Tekst 'As' wystapil:\n";
cout << " " << ptr << '\n' << "\n\nNacisnij cokolwiek"; [???] DLA DOCIEKLIWYCH.
________________________________________________________________
getch();
return 0; * Argumenty funkcji - zawsze w tej samej kolejno ci!
} Kiedy wywołujesz gotow funkcj - np. strstr(), argumenty
funkcji musz by podane zawsze w tej samej kolejno ci (tak, jak
Inn metod zastosowania funkcji manipuluj cych ła cuchami
tekstowymi mo e by "obróbka" tekstu wprowadzonego przez funkcja "si spodziewa"). Wywołanie funkcji:
u ytkownika. Nast pny program przykładowy pozwala u ytkownikowi
wprowadzi tekst do przeszukiwania (odpowiednik listy) i tekst pointer = strstr(string, substring, 3);
do wyszukania (odpowiednik imienia). W wyniku wyszukania
wskazanego ła cucha program wy wietla list pocz wszy od powiedzie si i funkcja zadziała zgodnie z oczekiwaniami.
wyszukanego pierwszego wyst pienia zadanego ła cucha znaków. Natomiast wywołanie funkcji tak:
63
spowoduje bł d przy kompilacji programu. identyfikacyjny pliku).
* Przy manipulacji stringami kłopoty mog sprawia spacje, b d Zestaw "narz dzi" potrzebnych nam do pracy to:
ich brak. Dla przykładu przy sklejaniu dwóch ła cuchów
tekstowych warto dla czytelno ci doda spacj , by nie uzyskiwa IO.H - prototypy funkcji obsługi WEj cia/WYj cia (ang.
napisów typu: WaldekKowalski. Łatwo mo na przegapi i inne Input/Output=IO);
ograniczniki (ang. delimiter).
FCNTL.H - plik zawieraj cy definicje wymienionych poni ej
* Ocena długo ci tekstu. stałych:
Szczególnie przewiduj cy i ostro ny musi by programista wtedy, O_BINARY - otwarcie pliku w trybie binarnym;
gdy ła cuch b dzie wprowadzany przez u ytkownika programu. O_TEXT - otwarcie pliku w trybie tekstowym;
O_RDONLY (Open for Read Only) - otwórz tylko do odczytu;
O_WRONLY (...Write Only) - tylko dla zapisu;
LEKCJA 19: KILKA INNYCH PRZYDATNYCH FUNKCJI. O_RDWR (Reading and Writing) dozwolony zapis i odczyt;
________________________________________________________________
STAT.H - zawiera definicje stałych
W trakcie tej lekcji dowiesz si , jak zapisa teksty na dysku i S_IREAD - plik tylko do odczytu (przydatne dla funkcji creat);
jak jeszcze mo na nimi manipulowa przy pomocy gotowych funkcji S_IWRITE - tylko zapis (przydatne dla funkcji creat);
Borland C++.
________________________________________________________________ FUNKCJE:
int open(p1, p2, p3) - trójparametrowa funkcja otwieraj ca plik;
Program poni ej demonstruje zastosowanie trzech przydatnych (parametry patrz przykład) zwraca do programu Wynik = -1
funkcji: (operacja zako czona niepowodzeniem - np. nie ma pliku)
lub Wynik = File Descriptor - numer pliku przekazany przez DOS.
[P072.CPP] int creat(p1, p2) - funkcja tworz ca nowy plik;
int read(...) - funkcja czytaj ca z pliku;
#include <conio.h> int write(...) - funkcja zapisu do pliku;
imt close(...) - zamkni cie pliku.
int main(void)
{ Po uruchomieniu program otwiera automatycznie trzy standardowe
int i, x = 0, y = 0; pliki, zwi zane z urz dzeniami:
clrscr(); 0 - stdin - standardowy plik wej ciowy (norm. klawiatura
for (i = 1; i < 10; i++) konsoli);
{ 1 - stdout - standardowy plik wyj ciowy (norm. monitor);
y = i; 2 - stderr - standardowy plik wyj ciowy - diagnostyczny
x = 5*i; (komunikaty o bł dach).
textbackground(16-i);
textcolor(i); [S] STD...
gotoxy(x, y); STandarD INput - standardowe wej cie.
cprintf("Wspolrzedne: x=%d y=%d", x, y); STD OUTput - standardowe wyj cie.
getch(); STD ERRors - plik diagnostyczny.
}
return 0; //[P072-2.CPP]
}
# include <stdio.h>
textbackground() - ustaw kolor tła pod tekstem # include <conio.h>
texcolor() - ustaw kolor tekstu # include <SYS\STAT.H> //Duze litery tylko dla podkreslenia
gotoxy() - rozpocznij drukowanie tekstu od punktu o # include <FCNTL.H>
współrz dnych ekranowych # include <IO.H>
x - numer kolumny (w normalnym trybie: 1-80)
y - numer wiersza (w normalnym trybie: 1-25) char *POINTER;
int IL_znakow, DLUG_pliku, TRYB_dostepu, Wynik, i;
[Z] int Plik_1, Plik_2;
________________________________________________________________ char BUFOR[20] = {"TEKST DO PLIKU"};
1. Rozmie na ekranie napisy i znaki semigraficzne tworz ce char STOS[3], ZNAK='X';
rysunek tabelki.
2. Opracuj program, w którym pojedyncze znaki, b d napisy b d main()
porusza si po ekranie. {
3. Spróbuj przyspieszy działanie swojego programu z POINTER = &BUFOR[0];
poprzedniego zadania poprzez wstawk w assemblerze.
________________________________________________________________ printf("Wloz dyskietke do A: i nacisnij cos...\n");
Przykładowy program wykonuje nast puj ce czynno ci: printf("\n Teraz odczytam te liczby z pliku \n");
Plik=open("A:\PROBA.DAT", O_RDONLY);
1. Tworzy plik a:\plik1.dat (potrzebny dost p do dyskietki a:). Dlug_Pliku=lseek(Plik, 0, SEEK_END);
2. Tworzy plik a:\plik_2.dat. for (i=Dlug_Pliku-dwa_bajty; i>=0; i-=2)
3. Otwiera plik a:\plik1.dat w trybie binarnym tylko do zapisu. {
(ZWRÓ UWAG , e tryb binarny nie przeszkadza zapisa tekstu.) lseek(Plik, i, SEEK_SET);
4. Dokonuje zapisu do pliku. read(Plik, &M, dwa_bajty);
5. Zamyka plik a:\plik1.dat. printf("%d, ", M);
6. Otwiera plik1.dat w trybie binarnym tylko do odczytu. }
7. Otwiera plik_2.dat tylko do zapisu. close(Plik);
8. Kopiuje plik1.dat do plik_2.dat dodaj c spacje. getch();
65
Interpreter rozkazów systemu DOS ładuje programy do pami ci
posługuj c si funkcj systemow nr 75 (4B hex). Wszystko jest /* Funkcje grupy spawn...() : spawnl() */
proste dopóki mamy do czynienia z programem "krótkim" typu
*.COM. Je li jednak e program uruchamiany jest w wersji # include <process.h>
"długiej" - *.EXE, dowolna mo e by nie tylko długo pliku, ale # include <stdio.h>
# include <conio.h>
tak e pocz tkowa zawarto rejestrów CS, SS, SP i IP. W plikach
typu *.EXE pocz tek bloku PSP wskazuj rejestry DS (DS:0000) i void main()
ES. W Borland C++ masz do dyspozycji specjaln funkcj getpsp() {
przy pomocy której mo esz uzyska dost p do bloku PSP programu. int rezultat;
Krótki przykład zastosowania tej funkcji poni ej: rezultat = spawnl(P_WAIT, "program.exe", NULL);
if (rezultat == -1)
/* Przykład zastosowania funkcji getpsp(): */ {
perror(" Fiasko !");
# include <stdio.h> exit(1);
# include <dos.h> }
}
main()
{
static char TAB[128]; /* Funkcja spawnle() */
char far *ptr;
int dlugosc, i; # include <process.h>
# include <stdio.h>
printf("Blok PSP: %u \n", getpsp()); # include <conio.h>
Poni ej kilka prostych przykładów uruchamiania jednych procesów Je li program rezydentny jest niewielki (kod < 64 K), mo emy
przez inne w Borland C++: zako czy program posługuj c si przerywaniem INT 39 (27 hex).
Je li natomiast zamierzamy posługiwa si dłu szymi programami,
/* Funkcja execv(): uruchomienie programu "potomnego"*/ mamy do dyspozycji funkcj systemow nr 49 (31 hex). Nale y tu
zwróci uwag , e zako czenie programu w taki sposób (z
# include <process.h> pozostawieniem w pami ci) nie spowoduje automatycznego
# include <stdio.h> zamkni cia plików, a jedynie opró nienie buforów. Programy
# include <errno.h> rezydentne dzieli si umownie na trzy kategorie:
void main(int argc, char *argv[]) [BP] - background process - procesy działaj ce "w tle";
{ [SV] - services - programy usługowe - np. PRINT;
int i; [PP] - pop up programs - uaktywniane przez okre lon kombinacj
klawiszy;
printf("Parametry uruchomieniowe:");
for (i=0; i<argc; i++) System DOS dysponuje tzw. przerywaniem multipleksowym
printf("\n%d) %s", i, argv[i]); (naprzemiennym) wykorzystywanym cz sto przez programy
rezydentne. Jest to przerywanie nr INT 47 (2F hex). MS DOS
printf("Przekazuje parametry do procesu 2 par_1, par_2...\n"); załatwia takie problemy funkcjami nr 37 (25 hex) - zapisanie
execv("CHILD.EXE", argv); wektora przerywania i 53 (35 hex) - odczytanie wektora
.... przerywania.
exit (2);
} Z jakich funkcji C++ mo na skorzysta ?
66
void interrupt ( *oldhandler)(void); 183 - APPEND.EXE
int licznik = 0;
Identyfikator programu TSR jest przekazywany za po rednictwem
void interrupt handler(void) rejestru AH.
{
/* Inkrementacja globalnej zmiennej licznik */ System DOS jest na razie systemem w zasadzie jednozadaniowym i
licznik++; jednou ytkownikowym, w którym zasoby s przydzielane procesom
kolejno (ang. serially reusable resources). Aby uchroni si
/* Wywolujemy stary "handler" zegara */ przed potencjalnym konfliktem, powinni my upewni si , czy DOS
oldhandler(); "nic nie robi". Cz sto stosowan "sztuczk techniczn " jest
} zastosowanie flag ErrorMode i InDos systemu oraz wykorzystanie
mechanizmów przerywa nr 36 i 40 (24 i 28 hex). Przydatn
void main() informacj jest tak e identyfikator programu - PID. Na tak
{ ewntualno Borland C++ dysponuje makrem getpid zdefiniowanym w
/* Zapami taj poprzedni wektor przerywania 28 */ pliku nagłówkowym <PROCESS.H>:
oldhandler = getvect(28);
# define getpid() (_psp)
/* Zainstaluj now funkcje obslugi przerywania */
setvect(28, handler); Inn przydatn funkcj mo e okaza si keep() (ang. keep
resident - pozosta rezydentny). Oto krótki przykład
/* Inkrementuj licznik */ zastosowania tej funkcji - znów z wykorzystaniem przerywa
for (; licznik < 10; ) printf("licznik: %d\n",licznik); zegarowych.
wywołaniu jest zawsze ZERO a przy nast pnych wywołaniach (po Zmieni si tylko tyle, e powtórnie wywołana funkcja setjmp()
powrocie z procesu) jest równa parametrowi "int liczba" zwróci tym razem warto 1, zatem warunek b dzie spełniony i
przekazanemu do ostatnio wywołanej funkcji longjmp(). rozpocznie si proces1():
for (i = 0; i < max; i++) Je li stosujemy w programie p tle zagnie d one (ang. nested
T[i] = i; loops), to p ta zorganizowana tak:
stosuj c zamiast if-else operator ? : mo emy to zapisa tak: * rozszerzony zestaw słów kluczowych (ang. keywords):
** nowe słowa kluczowe C++:
(x == MAXIMUM) ? (x = 0) : (x++);
class - klasa,
Mno enie jest zwykle troch szybsze ni dzielenie. Zapis delete - skasuj (dynamicznie utworzony obiekt),
friend - "zaprzyja nione" funkcje z dost pem do danych,
a = b / 10; inline - wpleciony (funkcje przeniesione w formie rozwini tej
do programu wynikowego),
mo na zatem zast pi szybszym: new - utwórz nowy obiekt,
operator - przyporz dkuj operatorowi nowe działanie,
a = b * .1; private - dane i funkcje prywatne klasy (obiektu), do których
zewn trzne funkcje nie maj prawa dost pu,
Je li mamy do czynienia ze stał STALA, to zapis w programie protected - dane i funkcje "chronione", dost pne z
ograniczeniami,
y = x / STALA; --> y = x * (1.0 / STALA); public - dane i funklcje publiczne, dost pne bez ogranicze ,
template - szablon,
z pozoru bzdurny spowoduje w wi kszo ci implementacji this - ten, pointer wskazuj cy bie cy obiekt,
wyznaczenie warto ci mno nika 1.0/STALA przez kompilator na virtual - funkcja wirtualna, abstrakcyjna, o zmiennym
etapie kompilacji programu (compile-time), a w ruchu (run-time) działaniu.
b dzie obliczany iloczyn zamiast ilorazu.
* nowe operatory (kilka przykładów ju widzieli my), np.:
W programach cz sto stosuje si flagi binarne (jest-nie ma). C++ << - wy lij do strumienia wyj ciowego,
>> - pobierz ze strumienia wej ciowego.
stosujemy jako flagi zmienne typu int lub char a w Windows BOOL. * nowe typy danych:
klasy,
Je li we miemy pod uwag fakt, e operatory relacji generuj obiekty,
warto ci typu TRUE/FALSE, typowy zapis: abstrakcyjne typy danych (ang. ADT).
* nowe zasady posługiwania si funkcjami:
if (a > b) funkcje o zmiennej liczbie argumentów,
Flaga = 1; funkcje "rozwijane" inline,
else funkcje wirtualne, itp.;
Flaga = 0;
Przede wszystkim (i od tego wła nie rozpoczniemy) zobaczymy
zast pimy krótszym funkcje o nowych mo liwo ciach.
Taki krótszy zapis NIE ZAWSZE powoduje wygenerowanie szybszego Funkcje uzyskuj w C++ znacznie wi cej mo liwo ci. Przegl d
kodu. Jest to zale ne od specyfiki konkretnej implementacji. rozpoczniemy od sytuacji cz sto wyst puj cej w praktyce
Je li natomiast upro cisz swój program tak: programowania - wykorzystywania domy lnych (ang. default)
parametrów.
if (x > 1) a = 3; --> a = 3 * (x > 1);
else a = 0; FUNKCJE Z DOMY LNYMI ARGUMENTAMI.
spowoduje to wyra ne spowolnienie programu (mno enie trwa). Prototyp funkcji w C++ pozwala na podanie deklaracji domy lnych
warto ci argumentów funkcji. Je li w momencie wywołania funkcji
Kompilator C++ rozró nia dwa rodzaje wyra e : w programie jeden (lub wi cej) argument (ów) zostanie pomini te,
* general expressions - wyra enia ogólne - zawieraj ce zmienne i kompilator wstawi w puste miejsce domy ln warto argumentu.
wywołania funkcji, których warto ci nie jest w stanie okre li Aby uzyska taki efekt, prototyp funkcji powinien zosta
na etapie kompilacji i zadeklarowany w programie np. tak:
* constant expressions - wyra enia stałe, których warto mo na
wyznaczy na etapie kompilacji. void Funkcja(int = 7, float = 1.234);
74
[!!!] Argumentów mo e ubywa wył cznie kolejno. Sytuacja: {
int x = 22; //Zmienna lokalna funkcji main
Funkcja(5.127); // LE cout << ::x << " <-- To jest globalny ::x \n";
Funkcja(99); //DOBRZE cout << x << " <-- A to lokalny x \n";
daj_x();
jest w C++ niedopuszczalna. Kompilator potraktuje liczb 5.127
jako pierwszy argument typu int i wyst pi konflikt. return 0;
}
[P079.CPP]
void daj_x(void)
#include <iostream.h> {
cout << "To ja funkcja daj_x(): \n";
void fun_show(int = 1234, float = 222.00, long = 333L);
cout << ::x << " <-- To jest globalny ::x \n";
main() cout << x << " <-- A to lokalny x \n";
{
fun_show(); // Trzy arg. domyslne int x = 333;
fun_show(1); // Pierwszy parametr cout << "A to moja zmienna lokalna - automatyczna ! \n";
fun_show(11, 2.2); // Dwa parametry cout << x << " <-- tez x ";
fun_show(111, 2.22, 3L); // Trzy parametry }
return 0;
} Program wydrukuje tekst:
int x, y, z; [P081.CPP]
...
main() # include <iostream.h>
{
... enum ciuchy
z = x + y + 1; {
... niewymowne = 1, skarpetka, trampek, koszula, marynarka,
} czapa, peruka, koniec
};
mo e zosta zast piony deklaracj w miejscu zastosowania (w tym
np. wewn trz p tli): main()
{
main() ciuchy n;
{ do
... {
for ( int i = 1; i <= 10; i++) cout << "\nNumer ciucha ? --> (1-7, 8 = quit): ";
cout << "Biezace i wynosi: " << i; cin >> (int) n;
...
} switch (n)
{
Nale y jednak pami ta o pewnym ograniczeniu. Zmienne case niewymowne: cout << "niewymowne";
deklarowane poza funkcj main() s traktowane jako zmienne break;
globalne i s widoczne (dost pne) dla wszystkich innych case skarpetka: cout << "skarpetka";
elementów programu. Zmienne deklarowane wewn trz bloku/funkcji break;
s zmiennymi lokalnymi i mog "przesłania " zmienne globalne. case trampek: cout << "trampek";
Je li wielu zmiennym nadamy te same nazwy-identyfikatory, mo emy break;
case koszula: cout << "koszula";
prze ledzi mechanim przesłaniania zmiennych w C++. W break;
przykładzie poni ej zastosowano trzy zmienne o tej samej nazwie case marynarka: cout << "marynarka";
"x": break;
case czapa: cout << "czapa";
[P080.CPP] break;
//Program demonstruje przesłanianie zmiennych case peruka: cout << "peruka";
break;
#include <iostream.h> case koniec: break;
default:
int x = 1; //Zmienna globalna cout << "??? Tego chyba nie nosze...";
void daj_x(void); //Prototyp funkcji }
} while (n != koniec);
main()
75
return 0; int n = rand() % 100;
} ...
________________________________________________________________
Zwró uwag w programie na forsowanie typu (int) przy pobraniu
odpowiedzi-wyboru z klawiatury. Poniewa w C++ "ciuchy" stanowi W programie przykładowym funkcje z STDLIB.H zostan skompilowane
nowy (zdefiniowany przed chwil ) typ danych, do uto samienia ich przez kompilator C. Okre lenie trybu kompilacji deklaracj
extern "C" jest umieszczane zwykle nie wewn trz programu
z typem int niezb dne jest wydanie takiego polecenia przy głównego a w doł czanych plikach nagłówkowych *.H. Jest to
pobieraniu danych ze strumienia cin >> . W opcjach pracy mo liwo szczególnie przydatne, je li dysponujesz bibliotekami
kompilatora mo esz wł czy /wył czy opcj "Treat enums as int" funkcji dla C a nie masz ch ci, czasu, b d mo liwo ci
(traktuj typ enum jak int) i wtedy pomin forsowanie typu w przerabiania ich na wersj przystosowan do wymaga C++. Drugi
programie. przykład poni ej zajmuje si sortowaniem krewnych przy pomocy
funkcji C qsort().
JEDNOCZESNE ZASTOSOWANIE DWU KOMPILATORÓW.
[P082.CPP]
Jak ju wspomnieli my wcze niej kompilator C++ składa si w
istocie z dwu ró nych kompilatorów: # include <iostream.h>
# include <stdlib.h>
* kompilatora C wywoływanego standardowo dla plików *.C, # include <string.h>
* kompilatora C++ wywoływanego standardowo dla plików *.CPP.
extern "C" int comp(const void*, const void*);
Oba kompilatory stosuj RÓ NE metody tworzenia nazw zewn trznych
main()
(ang. external names). Je li zatem program zawiera moduł, w {
którym funkcje zostały przekompilowane w trybie int max;
charakterystycznym dla klasycznego C - C++ powinien zosta o tym for(;;)
{
poinformowany. Dla przykładu, C++ cout << "\n Ilu krewnych chcesz posortowac? (1...6): ";
cin >> max;
* kategorycznie kontroluje zgodno typów argumentów, if( max > 0 && max < 7) break;
* na swój własny u ytek dodaje do nazw funkcji przyrostki (ang. cout << "\n Nic z tego...";
suffix) pozwalaj ce na okre lenie typu parametrów, }
* pozwala na tworzenie tzw. funkcji polimorficznych (kilka static char* krewni[] =
ró nych funkcji o tej samej nazwie), itp. {
"Balbina - ciotka",
Zwykły C tego nie potrafi i nie robi. Dlatego te do "Zenobiusz - kuzyn",
wprowadzenia takiego podziału kompetencji nale y czasem "Kleofas - stryjek",
zastosowa deklaracj extern "C". Funkcja rand() w programie "Ola - kuzynka (ach)",
poni ej generuje liczb losow . "Waleria - tez niby ciotka",
"Halina - stryjenka"
[P081.CPP] };
Pami dzielona jest w obszarze programu na nast puj ce bloki: struct Data
{
___________________ int dzien;
niskie adresy --> Ngłówek programu I. int miesiac;
Adres startowy int rok;
KOD: Kod programu };
___________________
Zmienne statyczne II. void main()
DANE: 1. Zainicjowane Zmienne globalne {
___________________ Data *pointer = new Data;
Zmienne statyczne III. /* Dekl. wskaznik do struct typu Data */
DANE: 2. Niezainicjowane Zmienne globalne /* Przydziel pamiec dla struktury */
___________________
STERTA: (heap) W miar potrzeby IV. pointer -> miesiac = 11; // pole "miesiac" = 11
ro nie w dół. pointer -> dzien = 3;
Tu operuj funkcje pointer -> rok = 1979;
malloc(), free().
___________________ cout << "\n URODZINY CORKI: ";
POLE NICZYJE: V. cout << pointer -> dzien << '.';
cout << pointer -> miesiac << ". ";
___________________ cout << "co rok ! od " << pointer -> rok << " r.";
W miar potrzeby VI.
STOS: (stack) ro nie w gór . delete pointer; //Skasuj wskaznik - zwolnij pamiec.
wysokie adresy --> ___________________ }
W obszarze kodu (I.) znajduj si instrukcje. Na stosie Program tworzy w pami ci (dokł. na stercie) struktur typu Data
przechowywane s : bez nazwy. O któr struktur chodzi i gdzie jej szuka w pami ci
Na stercie natomiast przy pomocy funkcji (a jak przekonamy si oznacza jednoczesn deklaracj i zainicjowanie wska nika.
za chwil - tak e operatorów C++) mo emy przydziela pami dla
ró nych obiektów tworzonych w czasie pracy programu (ang. TWORZENIE DYNAMICZNYCH TABLIC O ZMIENNEJ WIELKO CI.
run-time memory allocation) - np. tworzy bufory dla ła cuchów,
tablic, struktur itp.. Zwró uwag , e obszar V. - POLE NICZYJE Je li mamy dane wył cznie jednego typu (tu: int), zastosowanie
mo e by w czasie pracy programu stopniowo udost pniany dla struktury jest wła ciwie przysłowiowym "strzelaniem z armaty do
stosu (który rozrasta si "w gór "), albo dla sterty (która wróbli". Trójelementowa tablica typu
rozrasta si "w dół"). W przykładowym programie poni ej podano,
w którym obszarze pami ci zostanie umieszczony dany element int TAB[3];
programu.
zupełnie nam wystarczy. Utworzymy j jednak nie jako tablic
# include <alloc.h> globaln (b d statyczn ) w obszarze pami ci danych, lecz
int a; // III. dynamicznie - na stercie.
int b = 6; // II.
[P084.CPP]
main()
{ # include "iostream.h"
char *Dane;
... main()
float lokalna; // VI. {
... int *pointer = new int[3]; // Przydziel pamiec
Dane = malloc(16); // IV.
... pointer[0] = 3; // Tabl_bez_nazwy[0] - dzien
} pointer[1] = 11; // Tabl_bez_nazwy[1] - miesiac
pointer[2] = 1979;
OPERATORY new I delete.
cout << "Data urodzenia: ";
Operatory new i delete działaj podobnie do pary funkcji for(int i = 0; i < 3; i++)
malloc() - free(). Pierwszy przyporz dkowuje - drugi zwalnia cout << pointer[i] << '.';
pami . Dokładniej rzecz bior c
delete pointer;
- operator new mo e zosta zastosowany wraz ze wska nikiem do }
bloku danych okre lonego typu:
* struktury danych, Uwa ny Czytelnik doszedł zapewne do wniosku, e skoro tablica
* tablicy, itp. (wkrótce zastosujemy go tak e w stosunku do tworzona jest dynamicznie w ruchu programu (run-time), to
klas i obiektów); kompilator nie musi zna na etapie kompilacji programu
- przyporz dkowuje pami blokowi danych; (compile-time) wielko ci tablicy! Id c dalej, program powinien
- przypisuje pocz kowy adres bloku pami ci wska nikowi. tak technik tworzy tablice o takiej wielko i, jakiej w ruchu
- operator delete zwalnia pami przyporz dkowan poprzednio za yczy sobie u ytkownik. Spróbujmy zrealizowa to praktycznie.
blokowi danych,
[P085.CPP]
Operatory new i delete mog współdziała z danymi wieloma typami
# include <conio.h>
danych (wcale nie tylko ze strukturami), jednak e rozpoczniemy # include <stdlib.h>
77
# include <iostream.h> qsort(pointer, i, sizeof(char *), Fporownaj);
/* Wypelniamy tablice liczbami naturalnymi: */ Tworzymy dynamicznie przy pomocy operatora new bezimienn
for (i = 0; i < size; i++) tablic składaj c si z tablic ni szego rz du (ła cuch znaków
pointer[i] = i; to te tablica tyle, e jednowymiarowa - ma tylko długo ).
cout << "\n TABLICA: \n"; Zwró uwag , e w C++ wska nik do wska nika (**pointer)
odpowiada konstrukcji "tablica składaj ca si z tablic". Aby
/* Sprawdzamy zawartosc tablicy: */ program uczyni bardziej pogl dowym spolszczymy nazwy funkcji
for (i = 0; i < size; i++) przy pomocy preprocesora.
cout << " " << pointer[i];
[P087.CPP]
char k = getch();
if(k == 'a') break; # define Fporown_string strcmp
delete pointer; # define Fkopiuj_string strcpy
} # define Fsortuj qsort
}
# include <stdlib.h>
Twój dialog z programem powinien wygl da nast puj co: # include <string.h>
# include <iostream.h>
Podaj wielkosc tablicy (1...100) --> 20
TABLICA:
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 extern "C"
18 19 {
Podaj wielkosc tablicy (1...100) --> 100 int Fporownaj(const void* x, const void* y)
TABLICA: {
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 return (Fporown_string(*(char **)x, *(char **)y));
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 }
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 }
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
main()
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 {
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 cout << "Wpisz maksymalna ilosc imion --> ";
Skoro dynamiczne tablice o zmiennej wielko ci "chodz ", mo emy int ilosc, i;
wykorzysta to w bardziej interesuj cy sposób. cin >> ilosc;
// Proba nieautoryzowanego dostepu do danych prywatnych obiektu: typ (tzw. agregat) zawieraj cy praktycznie zawsze i dane
// cout << Ciapek.schowek; "tradycyjnych" typów i funkcje (nazywane "metodami"). Podobnie
// printf("%d", Ciapek.schowek); jak definiuj c struktur tworzysz nowy formalny typ danych, tak
// nie powiedzie sie i tu - definiuj c klas tworzysz nowy typ danych. Je li
zadeklarujesz u ycie zmiennych danego typu formalnego, takie
Powiedzie sie natomiast próba dost pu do "zwykłej" zmiennej - zmienne to wła nnie obiekty. Innymi słowy, klasy stanowi
dowoln metod - np.: definicje formalnego typu, natomiast obiekty - to zmienne danego
Je li podejmiesz prób odwołania si do "zakapsułkowanych" Zamiast słowa struct stosujemy przy klasach słowo class.
danych w zwykły sposób - np.:
class Klasa
cout << Ciapek.schowek; {
int prywatna_tab[80]
kompilator wy wietli komunikat o bł dzie: public:
int dane;
Error: 'Zwierzak::schowek' is not accessible in function main() void Inicjuj(void);
(pole schowek struktury typu Zwierzak (np. str. Ciapek) nie jest int Funkcja(int arg);
};
dost pne z wn trza funkcji main(). )
Nasza pierwsza wiadomie tworzona klasa nazywa si "Klasa" i
Do klas i obiektów ju tylko male ki kroczek. Jak przekonasz si stanowi nowy formalny typ zmiennych. Je li zadeklarujesz zmienn
za chwil - struktura Ciapek jest ju wła ciwie obiektem, a typ takiej klasy (tego typu formalnego), to taka zmienna b dzie
danych Zwierzak jest ju wła ciwie klas obiektów. Wystarczy wła nie OBIEKTEM.
zamieni słowo "struct" na słowo "class".
Nasza pierwsza prawdziwa Klasa zawiera dane:
[CLASS.CPP]
prywatna_tab[80] - prywatn tablic ;
# include "iostream.h" dane - publiczn dan prost typu int;
oraz funkcje:
//w klasach schowek ma status private AUTOMATYCZNIE Inicjuj() - zainicjuj - utwórz obiekt danej klasy w pami ci;
//slowo private stalo sie zbedne Funkcja() - jaka funkcja publiczna.
main()
Je eli w dalszej cz ci programu chcieliby my zastosowa {
struktury takiego typu, deklaracja tych struktur musiałaby ...
wygl da tak: Klasa Obiekt;
Obiekt.dane = 13;
struct rodzaj_struktur ...
{
private: Tak sam metod , jak stosowali my do danych - pól struktury,
int prywatna_tab[80] mo emy odwoływa si do danych i funkcji w klasach i obiektach.
public:
int dane; main()
void Inicjuj(void); {
int Funkcja(int arg); ...
} str1, str2, .... , nasza_struktura; Klasa Obiekt;
Obiekt.dane = 13; Obiekt.Funkcja(44);
b d tak: ...
struct rodzaj_struktur Przyporz dkowali my obiektowi nie tylko dane, ale tak e funkcje
{ poprzez umieszczenie prototypów funkcji wewn trz deklaracji
private: klasy:
int prywatna_tab[80]
public: class Klasa
int dane; {
void Inicjuj(void); ...
int Funkcja(int arg); public:
}; ...
... void Inicjuj(void) /* Prototypy funkcji */
(struct) rodzaj_struktur str1, str2, .... , nasza_struktura; int Funkcja(int argument);
};
Słowo kluczowe struct jest opcjonalne. Mogliby my wi c
zadeklarowa struktur w programie, wewn trz funkcji main(): [!!!] UWAGA!
________________________________________________________________
struct rodzaj_struktur W C++ nie mo emy zainicjowa danych wewn trz deklaracji klasy:
{
private: class Klasa
int prywatna_tab[80] {
public: private:
int dane; int prywatna_tab[80] = { 1, 2, ... }; // LE !
void Inicjuj(void); public:
int Funkcja(int arg); int dane = 123; // ŁE !
}; ...
________________________________________________________________
main()
{ Inicjowanie danych odbywa si w programie głównym przy pomocy
... przypisania (dane publiczne), b d za po rednictwem funkcji
struct rodzaj_struktur nasza_struktura; nale cej do danej klasy i maj cej dost p do wewn trznych danych
//lub równowa nie:
rodzaj_struktur nasza_struktura; klasy/obiektu (dane prywatne). Inicjowania danych mog dokona
tak e specjalne funkcje - tzw. konstruktory.
Do pól struktury mo emy odwoływa si przy pomocy operatora
kropki (ang. dot operator). Podobnie dzieje si w przypadku Dane znajduj ce si wewn trz deklaracji klasy mog mie status
klas. Je li zadeklarujemy zmienn typu Klasa, to ta zmienna public, private, b d protected. Dopóki nie za dasz inaczej -
b dzie naszym pierwszym obiektem. domy lnie wszystkie elementy klasy maj status private. Je eli
cz obiektu jest prywatna, to oznacza, e aden element
class Klasa programu spoza obiektu nie ma do niej dost pu. W naszej Klasie
{ prywatn cz stanowi tablica zło ona z liczb całkowitych:
int prywatna_tab[80]
public: (default - private:) int prywatna_tab[80];
int dane;
void Inicjuj(void) Do (prywatnych) elementów tablicy dost p mog uzyska tylko
int Funkcja(int our_param); funkcje zwi zane (ang. associated) z obiektem danej klasy.
} Obiekt; Funkcje takie musz zosta zadeklarowane wewn trz definicji
danej klasy i s nazywane członkami klasy - ang. member
Podobnie jak wy ej, mo emy zadeklarowa nasz obiekt wewn trz functions. Funkcje mog mie status private i sta si dzi ki
funkcji main(): temu wewn trznymi funkcjami danej klasy (a w konsekwencji
równie prywatnymi funkcjami obiektów danej klasy). Jest to
class Klasa jedna z najwa niejszych cech nowoczesnego stylu programowania w
{ C++. Na tym polega idea hermetyzacji danych i funkcji wewn trz
int prywatna_tab[80] klas i obiektów. Gdyby jednak cała zawarto (i dane i funkcje)
public: znajduj ce si w obiekcie zostały dokładnie "zakapsułkowane", to
int dane;
void Inicjuj(void) okazałoby si , e obiekt stał si " lepy i głuchy", a w
int Funkcja(int argument); konsekwencji - niedost pny i kompletnie nieu yteczny dla
}; programu i programisty. Po co nam obiekt, do którego nie mo emy
82
odwoła si z zewn trz adn metod ? W naszym obiekcie, w
dost pnej z zewn trz cz ci publicznej zadeklarowali my zmienn definicja powinna wygl da tak:
całkowit dane oraz dwie funkcje - Inicjuj() oraz Funkcja().
Je li dane i funkcje maj status public, to oznacza, e mo emy void Inicjuj(char x) //Deklaracja zmiennej znak.
si do nich odwoła z dowolnego miejsca programu i dowolnym {
sposobem. Takie odwołania przypominaj sposób odwoływania si do licznik.znak = x; //x - wewn trzna zmienna funkcji
licznik.ile = 0;
elementów struktury: }
w programie w nast puj cy sposób: Po przerwaniu p tli przez u ytkownika wystarczy sprawdzi jaka
warto jest wpisana w polu licznik.ile i mo emy wydrukowa
//Przypisanie (zainicjowanie pola struktury) wynik zliczania wyst pie litery 'A' we wprowadzonym tek cie.
licznik.znak = 'A';
cin >> licznik.znak; cout << "\nLitera " << licznik.znak
<< " wyst pila " << licznik.ile
//Odczyt (wyprowadzenie) bie . zawarto ci pola struktury. << " razy.";
cout << licznik.znak;
Program w cało ci b dzie wygl dał tak:
Potrzebna nam b dzie funkcja, przy pomocy której przeka emy do
struktury informacj , jaki znak powinien by zliczany. Nazwijmy [P092.CPP]
t funkcj Inicjuj(). Funkcja Inicjuj() powinna nam zainicjowa
pole struktury tzn. po przekazaniu jej jako argumentu tego # include <iostream.h>
znaku, który ma podlega zliczaniu, funkcja powinna "przenie " # include <ctype.h> //Prototyp f. toupper()
znak i zapisa go w polu licznik.znak naszej roboczej struktury.
struct Licznik
Wywołanie funkcji w programie powinno wygl da tak: {
char znak;
main() int ile;
{ } licznik;
....
Inicjuj('A'); void Inicjuj(char x)
.... {
//UWAGA: Nie tak: licznik.znak = x;
//licznik.Inicjuj() - funkcja jest zewn trzna ! licznik.ile = 0;
}
Aby funkcja inicjuj ca pole struktury zadziałała prawidłowo, jej
void PlusJeden(void)
83
{ oznacza dla C++, e funkcja jest członkiem klasy (ang. member
licznik.ile++; function). Logika C++ w tym przypadku wygl da tak:
}
* Prototypy funkcji nale y umie ci w definicji klasy.
void main() * Definicje funkcji mog znajdowa si w dowolnym miejscu
{ programu, poniewa operator przesłaniania :: pozwala rozpatrywa
char znak_we;
Inicjuj('A'); klas podobnie jak zmienne globalne.
cout << "\nWpisz tekst zawierajacy litery A"; * Wstawiaj c operator :: pomi dzy nazw klasy i prototyp funkcji
cout << "\nPierwzse wytapienie litery k lub K";
cout << "\n - oznacza Koniec zliczania: "; informujemy C++ e dana funkcja jest członkiem okre lonej klasy.
for(;;)
{ Funkcje - członkowie klas nazywane s cz sto METODAMI.
cin >> znak_we; Definicje klas i definicje funkcji - METOD s cz sto umieszczane
if (znak_we == 'k' || znak_we == 'K') break;
if(licznik.znak == toupper(znak_we)) PlusJeden(); razem - w plikach nagłówkowych. Je li posługujemy si tak
} metod , wystarczy doł czy odpowiedni plik dyrektyw # include.
Kompilator C++ skompiluje wtedy automatycznie wszystkie funkcje,
cout << "\nLitera " << licznik.znak
<< " wystapila " << licznik.ile które znajdzie w doł czonych plikach nagłówkowych.
<< " razy.";
} Mo emy przyst pi do utworzenia programu.
W C++ istnieje jednak e pewne do istotne ograniczenie - nie Licznik::Licznik(char x) //Def. konstruktora
mo emy zadeklarowa tablicy zło onej z obiektów posiadaj cych {
konstruktory, chyba e wszystkie konstruktory s bezparametrowe znak = x;
(typu default constructors). ile = 0;
}
Udoskonalmy teraz nasz program zliczaj cy wyst pienia w tek cie
litery a posługuj c si konstruktorem struktury. void main()
{
[P094.CPP] /* Wersja ze struktur */ Licznik licznik('A'); //Zainicjowanie obiektu licznik
# include <ctype.h> cout << "Sprawdzamy: znak ile? " << "\n\t\t"
# include <iostream.h> << licznik.Pokaz() << "\t";
cout << licznik.Efekt();
struct Licznik
{ cout << "\nWpisz tekst zawierajacy litery A";
private: cout << "\nPierwsze wytapienie litery k lub K";
char znak; cout << "\n - oznacza Koniec zliczania: ";
int ile; for(;;)
public: {
Licznik(char); //Konstruktor char znak_we;
void PlusJeden(void); cin >> znak_we;
char Pokaz(void); if (znak_we == 'k' || znak_we == 'K') break;
int Efekt(void); if(licznik.Pokaz() == toupper(znak_we))
}; licznik.PlusJeden();
}
Licznik::Licznik(char x) //Def. konstruktora
{ cout << "\nLitera " << licznik.Pokaz()
znak = x; << " wystapila " << licznik.Efekt()
ile = 0; << " razy.";
} }
cout << "Sprawdzamy: znak ile? " << "\n\t\t" Pora w tym miejscu zaznaczy , e C++ oferuje nam jeszcze jedno
<< licznik.Pokaz() << "\t"; specjalne narz dzie podobnej kategorii. Podobnie, jak do
cout << licznik.Efekt(); tworzenia (struktur) obiektów mo emy zastosowa konstruktor, tak
cout << "\nWpisz tekst zawierajacy litery A"; do skasowania obiektu mo emy zastosowa tzw. desruktor (ang.
cout << "\nPierwsze wytapienie litery k lub K"; destructor). Nazwy konstruktora i destruktora s identyczne z
cout << "\n - oznacza Koniec zliczania: "; nazw macie ystego typu struktur (macie ystej klasy), z tym, e
for(;;) nazwa destruktora poprzedzona jest znakiem "~" (tylda).
{
86
CO TO JEST DESTRUKTOR. destruktor zostanie wywołany automatycznie zawsze wtedy, gdy
obiekt przestanie by widoczny, istnienie destruktora w
Specjalna funkcja - destruktor (je li zadeklarujemy zastosowanie definicji typu struktur Stos pozwala na automatyczne wyzerowanie
takiej funkcji) jest wywoływana automatycznie, gdy program stosu. Deklarujemy destruktor podobnie do konstruktora, dodaj c
zako czy korzystanie z obiektu. Konstruktor towrzy, a destruktor przed nazw destruktora znak ~ (tylda):
(jak sama nazwa wskazuje) niszczy struktur (obiekt) i zwalnia struct Stos
przyporz dkowan pami . Przykład poni ej to program {
manipuluj cy stosem, rozbudowany tak, by zawierał i konstruktor ...
i destruktor struktury (obiektu). Zorganizujmy zarz dzanie public:
pami ci przeznaczon dla stosu w taki sposób: ...
~Stos(void);
struct Stos ...
{ }
private:
int *bufor_danych; Je li program zako czy si lub struktura przestanie by
int licznik; widoczna, zostanie wywołany destruktor struktury nasz_stos i
public: pami zostanie zwolniona. Praktycznie oznacza to, e mo emy
Stos(int ile_RAM); /* Konstruktor zwolni pami c przyporz dkowan strukturze w taki sposób:
int Pop(int *ze_stosu);
int Push(int na_stos); Stos::~Stos(void) //Definicja destruktora
}; {
free(bufor_danych);
gdzie: cout << "\n Destruktor: Struktury juz nie ma...";
*bufor_danych - wska nik do bufora (wypełniaj cego rol stosu), }
licznik - wierzchołek stosu, je li == -1, stos jest pusty.
Stos::Stos(...) - konstruktor inicjuj cy struktur typu Stos Od momentu zdefiniowania konstruktora i destruktora nie musimy
(lub obiekt klasy Stos), si ju przejmowa technicznymi szczegółami ich działania. W
ile_RAM - ilo pami ci potrzebna do poprawnego działanie stosu, dalszej cz ci programu destruktor i konstruktor b d wywoływane
*ze_stosu - wska nik do zmiennej, której nale y przypisa
warto zdj t wła nie ze stosu, automatycznie. Pozostaje nam pami ta , e
na_stos - liczba przeznaczona do zapisu na stos.
* stos mo e si nazywa dowolnie, a deklarujemy go tak:
Zajmijmy si teraz definicj konstruktora. Wywołuj c konstruktor
Stos nazwa_struktury;
w programie (deklaruj c u ycie w programie struktury typu Stos)
przeka emy mu jako argument ilo potrzebnej nam pami ci RAM w i dalej stosem mo emy posługiwa si przy pomocy funkcji:
bajtach. Do przyporz dkowznia pami ci na stercie dla naszego
stosu wykorzystamy funkcj malloc(). nazwa_struktury.Push()
nazwa_struktury.Pop()
Stos::Stos(int n_RAM) //Konstruktor - def.
{ Wszystkie wewn trzne sprawy stos b dzie załatwiał samodzielnie.
licznik = -1; W tym konkrertnym przypadku cz "prac organizacyjnych"
bufor_danych = (int *) malloc(n_RAM); zwi zanych z utworzeniem w pami ci struktury i zainicjowaniem
} pocz tkowych warto ci pól załatwi za nas konstruktor i
destruktor. Na tym wła nie polega idea nowoczesnego
Posługuj c si funkcj malloc() przyporz dkowujemy buforowi programowania w C++. Przykładowy program umieszcza liczby na
danych, w oparciu o który organizujemy nasz obiekt (na razie w stosie a nast pnie pobiera je ze stosu i drukuje na ekranie.
formie struktury) - stos 100 bajtów pami ci, co pozwala na Pełny tekst programu w wersji ze struktur - poni ej.
rozmieszczenie 50 liczb typu int (po 2 bajty ka da). Liczb
potrzebnych bajtów pami ci - 100 przekazujemy jako argument [P096.CPP]
konstruktorowi w momencie deklaracji struktury typu Stos. Nasza
struktura w programie b dzie si nazywa nasz_stos. # include <iostream.h>
# include <alloc.h>
main()
{ /* -----------------------poczatek pliku STOS.HPP------------ */
...
Stos nasz_stos(100);
... # define OK 1
stos przestaje by "widoczny" (ang. out of scope). Obiekt mo e Stos::~Stos(void) //Definicja destruktora
przesta by widoczny np. wtedy, gdy działa funkcja "nie {
widz ca" obiektu. Id c dalej tym torem rozumowania, je li free(bufor_danych);
87
cout << "\n Destruktor: Struktury juz nie ma..."; Stos::Stos(int n_RAM) //Konstruktor - def.
} {
licznik = -1;
bufor_danych = (int *) malloc(n_RAM);
int Stos::Pop(int* ze_stosu) cout << "Konstruktor: Inicjuje obiekt klasy Stos. ";
{ }
if(licznik == -1) return 0;
else *ze_stosu = bufor_danych[licznik--]; Stos::~Stos(void) //Definicja destruktora
return OK; {
} free(bufor_danych);
cout << "\n Destruktor: Obiektu juz nie ma...";
int Stos::Push(int na_stos) }
{
if(licznik >= 49) return 0; int Stos::Pop(int* ze_stosu)
else bufor_danych[++licznik] = na_stos; {
return OK; if(licznik == -1) return 0;
} else *ze_stosu = bufor_danych[licznik--];
/* --------------------------koniec pliku STOS.HPP----------- */ return OK;
}
Przed nazw typu struktury (klasy) bazowej (tu: Zwierzak) mo e Program w cało ci b dzie wygl dał tak:
pojawi si słowo okre laj ce zasady dost pu do danych i funkcji
[P099.CPP]
(tu: public).
# include <iostream.h>
[!!!] RÓ NIE MO NA DZIEDZICZY ...
________________________________________________________________ struct Zwierzak
* Je li u yjemy w tym miejscu słowa public (przy strukturach {
domy lne), to atrybuty dost pu zostan odziedziczone wprost. int nogi;
Oznacza to, e to, co było prywatne w strukturze bazowej void jedz();
zostanie przeniesione jako prywatne do struktury pochodnej, a void spij();
to, co było publiczne w strukturze bazowej zostanie przeniesione void oddychaj();
};
jako publiczne do struktury pochodnej. void Zwierzak::jedz(void) { cout << "Jem conieco...\n"; }
* Je li natomiast u yjemy w tym miejscu słowa private, to void Zwierzak::spij(void) { cout << "Cosik mi sie sni...\n"; }
wszystko, co struktura pochodna odziedziczy po strukturze void Zwierzak::oddychaj(void) { cout << "Dysze ciezko...\n"; }
bazowej stanie si w strukturze pochodnej prywatne.
________________________________________________________________ struct Slon : Zwierzak
{
Opracowanie przykładowego programu ilustruj cego mechanizm int flaga_ssak;
dziedziczenia rozpoczniemy od zdefiniowania bazowego typu void trabi();
struktur i struktury pochodnej. void tupie();
};
struct Zwierzak
{ void Slon::trabi(void) { cout << "Tra-ta-ta...\n"; }
int nogi; <-- dane void Slon::tupie(void) { cout << "Kroczem...na wschod\n"; }
Mimo, e tworz c struktur Sło nie zadeklarowali my w jej struct kolo: punkt //Str. pochodna - kolo(x, y, R)
składzie ani funkcji jedz(), ani spij(), ani danych nogi, mo emy {
int promien; //wspolrzedne srodka x,y dziedziczymy
zastosowa funkcj Choleryk.jedz(), poniewa Choleryk };
odziedziczył t funkcj po strukturze bazowej Zwierzak. Dzi ki
dziedziczeniu mo emy posługiwa si danymi i funkcjami struct elipsa: kolo //dziedziczymy x,y i promien
nale cymi do obu typów struktur - bazowego: Zwierzak i {
pochodnego: Slon. int mniejszy_promien; //Str. pochodna elipsa(x, y, R, r)
};
[???] A CO Z UNIAMI ?
_______________________________________________________________ punkt P; //deklarujemy trzy struktury
90
kolo C;
elipsa E; [P102.CPP]
DWU RÓ NYCH OJCÓW (!). W C++ takie dziedziczenie po dwu ró nych void Slon::trabi(void) { cout << "Tra-ta-ta...\n"; }
typach bazowych jednocze nie nazywa si DZIEDZICZENIEM void Slon::tupie(void) { cout << "Kroczem...na wschod\n"; }
WIELOBAZOWYM (ang. multi-base inheritance). A oto przykład
takiego dziedziczenia. void main()
{
[P101.CPP] Slon Obiekt;
/* obiekt Obiekt klasy Slon */
#include <iostream.h> Obiekt.nogi = 4; Obiekt.flaga_ssak = 1;
cout << "\nNogi odziedziczylem: " << Obiekt.nogi;
struct BAZOWA1 cout << "\nA teraz kolejno funkcje: \n";
{ //Struktura bazowa pierwsza Obiekt.jedz();
public: Obiekt.spij();
void Funkcja_a(void); Obiekt.oddychaj();
}; Obiekt.trabi();
Obiekt.tupie();
struct BAZOWA2 if(Obiekt.flaga_ssak) cout << "Jestem ssakiem !";
{ //Struktura bazowa druga }
public:
void Funkcja_b(void); Pami taj c o problemie domy lnego statusu członków
}; struktur/public i klas/private) mo emy przej do klas i
obiektów.
struct POCHODNA : BAZOWA1, BAZOWA2 //Lista "przodkow"
{ O KLASACH SZCZEGÓŁOWO.
public:
void Funkcja_c(void); Aby wykaza mo liwo modularyzacji programu zaprojektujemy
}; moduł w postaci pliku nagłówkowego. Moduł b dzie zawiera
definicj naszej prywatnej klasy obiektów ZNAK.
void BAZOWA1::Funkcja_a(void){cout << "To ja F_a().\n";}
void BAZOWA2::Funkcja_b(void){cout << "To ja F_b().\n";} Zaczynamy od danych, które b d nam potrzebne do tworzenia w
void POCHODNA::Funkcja_c(void){cout << "To ja F_c().\n";} programach (ró nych !) obiektów typu Znak.
Słowo public jest w strukturach zb dne. Zostało u yte wył cznie class ZNAK
z pobudek "dydaktycznych" - dla zwrócenia uwagi na status {
funkcji - członków struktury. char znak_dany;
public:
Zarówno pokole w schemacie dziadek-ojciec-syn, jak i struktur ZNAK(...);
(klas) bazowych w schemacie baza_1-baza_2-....-baza_n mo e by ...
wi cej ni 2.
Dane mog by prywatne, natomiast konstruktor i funkcje-metody
DZIEDZICZENIE KLAS. powinny by publiczne, by mo na było wywoływa je w programach.
Konstruktor b dziemy wywoływa w programach tak:
Oto "klasowo-obiektowa" wersja poprzedniego programu
przykładowego ze słonikiem Cholerykiem. Typy struktur Zwierzak i ZNAK Obiekt('a');
Slon nazwiemy klasami, (odpowiednio - klas bazow i klas Znaczy to: Utwórz w RAM obiekt klasy ZNAK pod nazw "Obiekt" i
pochodn ) a struktur Slon Choleryk nazwiemy obiektem. wytłumacz mu, e jest znakiem 'a'.
91
i zdefiniujmy te metody.
Konstruktor powinien pobiera od programu jeden argument typu
char i przekazywa go obiektowi klasy ZNAK na jego pole danych void ZNAK::Pokaz_sie(void)
znak_dany. Definicja konstruktora b dzie zatem wygl da tak: {
cout << znak_dany << '\a';
ZNAK::ZNAK(char x) }
{
znak_dany = x; void ZNAK::Znikaj(void)
} {
cout << "\b" << ' '; //'\b' == Back Space
Zakres dopuszczalnych znaków zaw zimy np. do kodów ASCII 65...90 }
(od A do Z). Je li u ytkownik "nie trafi", ustawimy zawsze "*" void ZNAK::Skacz(void)
(asterisk). Dodatkowo, dla "elegancji" zamienimy ewentualne małe {
for(int i = 0; i < 100; i++)
litery na du e. {
gotoxy(rand()%50, rand()%50);
ZNAK::ZNAK(char x) cout << znak_dany;
{ getch();
znak_dany = x; }
if(znak_dany < 65 || znak_dany >122) znak_dany = '*'; }
if(znak_dany > 97) znak_dany -= 32;
} Je li implementacj klasy ZNAK umie cimy w pliku nagłówkowym
92
void main() }
{
char litera; Ła cuch znaków jest widziany jako jednowymiarowa tablica
zawieraj ca dane typu znakowego, czyli w taki sposób:
clrscr();
cout << '\n' << "Podaj znak: "; char TABLICA[9] ={ "123456789" };
cin >> litera;
Definice powinny mie nast puj c posta :
ZNAK Obiekt(litera);
cout << "\nSTART" << "\n\n\n"; void KLASA::wydrukuj(char znak) {cout << znak;};
void KLASA::wydrukuj(int kodASCII) {cout << (char) kodASCII;};
getch(); void KLASA::wydrukuj(char *string) {cout << string;};
Obiekt.Pokaz_sie();
getch(); Zapis:
Obiekt.Znikaj();
getch(); cout << (char) kodASCII;
Obiekt.Skacz();
oznacza forsowanie typu - zamie typ int na typ char -
ZNAK Obiekt2; //To bedzie domyslny 'X' przyporz dkowanie kodowi ASCII - znaku. Wywołanie tej funkcji w
Obiekt2.Skacz(); programie mo e spowodowa ró ne działanie, w zale no ci od typu
} i ilo ci argumentów, z którym(i) funkcja zostaje wywołana.
Wywołania funkcji mog wygl da np. tak:
I tu ju wida pewne cechy nowoczesnego obiektowego stylu
programowania. Tym razem sprwdzenie, czy słowo class mo na KLASA Obiekt1, Obiekt2;
spokojnie zamieni na słowo struct pozostawim dociekliwym main() {
Czytelnikom. ...
Obiekt1.wydrukuj('A'); //Wydrukuje si litera A
Obiekt1.wydrukuj(99); //Wydrukuje si litera c
LEKCJA 29: FUNKCJE I OVERLOADING. Obiekt2.wydrukuj("napis"); //Wydrukuje si napis.
________________________________________________________________ ...
W trakcie tej lekcji dowiesz si , jak jeszcze w C++ mo na }
wykorzystywa funkcje.
________________________________________________________________ Taki sposób post powania umo liwia funkcjom wi ksz elastyczno
w C++ jedna funkcja mo e by definiowana wielokrotnie a ka da z i pozwala operowa bez konfliktów na ró nych rodzajach danych.
wersji funkcji mo e by przystosowana do obsługi innego typu
argumentów. C++ wybiera t wła ciw wersj funkcji J zyk C posiada funkcje słu ce do kopiowania ła cuchów
automatycznie. znakowych: strcpy() i strncpy(). Funkcja biblioteczna strncpy()
przerywa proces kopiowania po zako czeniu ła cucha ródłowego,
JEDNA NAZWA FUNKCJI - WIELE ZASTOSOWA . b d po skopiowaniu zadanej ilo ci znaków. Dzi ki mechanizmowi
overloadingu mo emy utworzy nasz własn funkcj
Overloading funkcji bywa czasem w podr cznikach dzielony na kopiuj_string(), która zale nie od sytuacji zadziała jak
odr bne zagadnienia: strcpy(), b d tak jak strncpy().
ródłowym tek cie programu nast puje wywołanie funkcji typu class Klasa
inline, to kompilator wstawia w to miejsce całe ciało funkcji {
(funkcje typu inline nie maj bezpo redniego ani wył cznego public:
odniesienia do obiektowego stylu programowania). Dla przykładu, inline void wydrukuj(char* a) { cout << a; }
je li nadaliby my naszej funkcji wydrukuj() status funkcji inline void wydrukuj(char z) { cout << z; }
inline, to fragment programu: inline void wydrukuj(int kod) { cout << (char) kod; }
};
[!!!] A CZY NIE MO NA WEWN TRZ KLASY ? Praktyczne zastosowanie w programie b dzie wygl da tak:
________________________________________________________________
Mo na. Je li umie cimy pełn definicj funkcji wewn trz [P106.CPP]
definicji klasy, to taka funkcja staje si AUTOMATYCZNIE funkcj
# include <iostream.h>
94
okre lonego znaku w strumieniu znaków wej ciowych (wczytywanym z
class Klasa
{ klawiatury). Tablica b dzie si składa z MAX == 26 elementów -
public: obiektów - liczników, po jednym dla ka dej du ej litery
Klasa(); alfabetu. Tablica b dzie nazywa si TAB[26]. Po zadeklarowaniu:
Klasa(char*);
Klasa(char, int);
}; nazwa_klasy TAB[MAX];
Hermetyzacja danych jest cenn zdobycz , ale od czasu do czasu Mo na to zapisa skuteczniej.
obiekty powinny dokonywa pomi dzy sob wymiany informacji, ...
tak e tych wewn trznych - prywatnych. Ten problem mo e sprawia cin >> znak;
programi cie troch kłopotów - nale y zatem po wi ci mu troch TAB[znak - 'A'].Skok_licznika(); //Inkrementacja licznika
uwagi. ...
Takie funkcje o specjalnych uprawnieniach - z mo liwo ci W wyniku działania programu otrzymamy zliczon ilo
odwoływania si do prywatnych danych wielu obiektów (a nie tylko wyst powania danej litery w strumieniu znaków wej ciowych.
/* inicjujemy liczniki: -------------------------------*/ Dzi ki zastosowaniu słowa "friend", funkcja Suma() jest
zaprzyja niona ze wszystkimi 26 obiektami, poniewa wszystkie
for(i = 0; i < MAX; i++) obiekty nale do tej klasy, w której zadeklarowali my funkcj :
{
TAB[i].Inicjuj('A' + i); class ...
} {
/* pracujemy - zliczamy: -------------------------------*/ ...
friend int Suma(...);
cout << "Wpisz ciag zankow zakonczony kropka [.]" << '\n'; ...
for(;;) } ... ;
{ char znak;
cin >> znak; Tablica TAB[MAX] zło ona z obiektów klasy Licznik została
if(znak == '.') break; zadeklarowana nazewn trz funkcji main() ma wi c status tablicy
for(i = 0; i < MAX; i++) GLOBALNEJ. Funkcja Suma() ma dost p do prywatnych danych
{ wszystkich obiektów, mo emy wi c zastosowa j w programie w
if(i == (znak - 'A')) TAB[i].Skok_licznika(); nast puj cy sposób:
}
} [P108.CPP]
/* sprawdzamy: ----------------------------------------*/
# include <ctype.h>
char sprawdzamy; # include <iostream.h>
cout << '\n' << "Podaj znak do sprawdzenia: " << '\n';
cin >> sprawdzamy; class Licznik
cout << "Wyswietlam wyniki zliczania: \n"; {
TAB[toupper(sprawdzamy) - 'A'].Pokazuj(); char moja_litera;
int ile;
return 0; public:
} void Inicjuj(char);
void Skok_licznika();
Je li chcieliby my zliczy ilo wszystkich wprowadzonych void Pokazuj();
znaków, powinni my zsumowa dane pobrane od wielu obiektów. friend int Suma(int);
}
Je li dane przechowywane w obiektach maj status danych const MAX = 26;
prywatnych, to dost p do tych danych mo e by utrudniony. Do Licznik TAB[MAX];
tego momentu dost p do danych prywatnych obiektu mogli my register int i;
uzyska tylko posługuj c si autoryzowan do tego metod -
własn funkcj wewn trzn tego obiektu. Ale wtedy nie mieli my main()
dost pu do danych innych obiektów a tylko do jednego - {
"własnego" obiektu funkcji. Je li zatem chcieliby my zsumowa /* inicjujemy liczniki: -------------------------------*/
zawarto ci wielu obiektów - liczników, to nale y do tego
zastosowa tzw. funkcj "zaprzyja nion " - friend function. for(i = 0; i < MAX; i++)
Je li deklaruj c funkcj zastosujemy słowo kluczowe friend, to {
taka zaprzyja niona z klas funkcja uzyska prawo dost pu do TAB[i].Inicjuj('A' + i);
prywatnych elementów danej klasy. Zadeklarujemy tak przykładow }
/* pracujemy - zliczamy: -------------------------------*/
zaprzyja nion funkcj o nazwie Suma(). Funkcja b dzie pobiera
jako parametr ilo obiektów do zsumowania i sumowa zawarto ci cout << "Wpisz ciag zankow zakonczony kropka [.]" << '\n';
wewn trznych liczników obiektów. for(;;)
{ char znak;
const MAX = 26; cin >> znak;
if(znak == '.') break;
class Licznik for(i = 0; i < MAX; i++)
{ {
char moja_litera; if(i == (znak - 'A')) TAB[i].Skok_licznika();
int ile; }
public: }
void Inicjuj(char); /* sprawdzamy: ----------------------------------------*/
void Skok_licznika();
void Pokazuj(); char sprawdzamy;
friend int Suma(int); cout << '\n' << "Podaj znak do sprawdzenia: " << '\n';
} TAB[MAX]; cin >> sprawdzamy;
cout << "Wyswietlam wyniki zliczania: \n";
Zadeklarowana w taki sposób zaprzyja niona funkcja ma prawo TAB[toupper(sprawdzamy) - 'A'].Pokazuj();
dost pu do prywatnych elementów wszystkich obiektów klasy
Licznik. Typowe zastosowanie funkcji typu friend polega wła nie cout << "\n Wszystkich liter bylo " << Suma(MAX);
na dost pie do danych wielu ró nych obiektów. Powinni my
96
return 0;
} static int TAB[] = {31,28,31,30,31,30,31,31,30,31,30,31};
void Licznik::Skok_licznika(void) W C++ mamy jeszcze jedn metod wymiany danych. Mo emy nada
{ elementom klas i obiektów status static (statyczny).
ile++; //Wiadomo o ktory obiekt chodzi
} WYMIANA INFORMACJI PRZY POMOCY DANYCH STATYCZNYCH.
Funkcja klasy friend odwołuje si do pól obiektów tak: Je li element klasy został zadeklarowany jako element statyczny
(przy pomocy słowa kluczowego static), to bez wzgl du na to jak
int Suma(int liczba) wiele obiektów danej klasy utworzymy, w pami ci b dzie istnie
{ TYLKO JEDEN EGZEMPLARZ (kopia) tego elementu. W przykładowym
... programie z obiektami-licznikami mo emy osi gn c taki efekt
suma += TAB[i].ile; nadaj c zmiennej ile (stan licznika) status static int ile:
/* - wymaga dodatkowo wskazania, o który obiekt chodzi - */
} class Licznik
{
Nale y pami ta , e dla funkcji kategorii friend wszystkie char moja_litera;
obiekty nale ce do danej klasy maj status public - s static int ile;
dost pne. ...
};
O ZAPRZYJA NIONYCH KLASACH.
Je li utworzymy wiele obiektów takiej klasy, to wszystkie te
W C++ mog by zaprzyja nione ze sob wzajemnie tak e klasy. obiekty b d posługiwa si t sam (wspóln !) zmienn ile. Dla
Pozwala to metodom zdefiniowanym wewn trz jednej z klas na przykładu, je li zechcemy zlicza ile razy w strumieniu danych
dost p do prywatnych danych obiektów innych klas. W przypadku wej ciowych pojawiły si np. znaki 'a' , 'b' i 'c', mo emy
zaprzyja nionych klas słowem kluczowym friend poprzedzamy nazw utworzy trzy obiekty - liczniki: licznik_a, licznik_b i
klasy (a nie ka dej zaprzyja nionej metody z osobna, cho licznik_c. wszystkie te liczniki b d posługiwa si wspóln
zamierzony skutek wła nie na tym polega). Oto praktyczny zmienn statyczn ile:
przykład zaprzyja nionych klas.
class Licznik
[P109.CPP] {
public:
# include <iostream.h> char moja_litera;
static int ile;
class Data1; //Deklaracja (a nie definicja!) klasy Licznik(char); //Konstruktor
...
class TEZ_DATA };
{
int dz, rok; Do zainicjownia obiektów posłu ymy si konstruktorem. Deklaracja
public:
TEZ_DATA() {} obiektu spowoduje automatyczne wywołanie kostruktora i
TEZ_DATA(int d, int y) { dz = d; rok = y;} zainicjowanie obiektu w pami ci. Przy okazji przekazujemy
void Pokazuj() {cout << '\n' << rok << '-' << dz;} obiektom znaki do zliczania.
friend Data1; //"zaprzyjazniona" klasa
}; Licznik licznik_a('a'), licznik_b('b'), licznik_c('c');
class Data1 //Tu DEFINICJA klasy Je li teraz w strumieniu wej ciowym pojawi si która z
{ interesuj cych nas liter (a, b, b d c), zostanie wywołana
int mc, dz, rok; wła ciwa wersja metody Skok_licznika():
public:
Data1(int m, int d, int y) { mc = m; dz = d; rok = y; } int main(void)
operator TEZ_DATA(); {
}; char litera;
97
... }
cin >> litera;
... void Licznik::Skok_licznika(void)
if(litera == licznik_a.moja_litera) licznik_a.Skok_licznika(); {
ile++;
if(litera == licznik_b.moja_litera) licznik_b.Skok_licznika(); }
mo emy do niego odwoływa si na dwa sposoby. Za po rednictwem Jak wida , program si myli. Wszystkie funkcje wy wietlaj
obiektów w taki sposób: (odwołuj si do) zawarto ci tego samego wspólnego pola.
[P110.CPP] Je eli funkcja jest tylko jedna, jej działanie nie zale y od
tego ile obiektów danej klasy zostało utworzone i jakie nazwy
# include "ctype.h" nadamy tym obiektom. W przykładowym programie powy ej "a si
# include "iostream.h" prosi", by nada status funkcji statycznej metodzie
wy wietlaj cej wyniki zliczania:
class Licznik
{ class Licznik
public: {
char moja_litera; ...
static int ile; static void Pokazuj(void);
Licznik(char); //Konstruktor ...
void Skok_licznika(); }
void Pokazuj();
}; Sprawdzenie, czy wtedy program przestanie "robi bł dy"
pozostawiamy bardziej dociekliwym Czytelnikom jako zadanie
void main() domowe.
{
/* inicjujemy liczniki: -------------------------------*/
Licznik licznik_a('a'), licznik_b('b'), licznik_c('c'); LEKCJA 31: PRZEKAZANIE OBIEKTÓW JAKO ARGUMENTÓW DO
FUNKCJI.
/* pracujemy - zliczamy: -------------------------------*/ ________________________________________________________________
W trakcie tej lekcji poznasz sposoby manipulowania obiektami
cout << "Wpisz ciag zankow zakonczony kropka [.]" << '\n'; przy pomocy funkcji. Poznasz tak e troch dokładniej referencje.
for(;;) ________________________________________________________________
{ char znak;
cin >> znak; Typowy sposób przekazywania argumentów do funkcji w C++ to
if(znak == '.') break; przekazanie przez warto (ang. by value). W przypadku obiektów
if (znak == licznik_a.moja_litera) licznik_a.Skok_licznika(); oznacza to w praktyce przekazanie do funkcji kopii obiektu. Jako
if (znak == licznik_b.moja_litera) licznik_b.Skok_licznika();
if (znak == licznik_c.moja_litera) licznik_c.Skok_licznika(); przykład zastosujemy program zliczaj cy wyst pienia znaków w
} strumieniu wej ciowym. Zmienimy w tym programie sposób
/* sprawdzamy: ----------------------------------------*/ wyprowadzenia wyników. Funkcji Pokazuj() przeka emy jako
argument obiekt. Obiekt-licznik zawiera w rodku t informacj ,
której potrzebuje funkcja - ilo zliczonych znaków. Zacznijmy
cout << "Wyswietlam wyniki zliczania: \n"; od zdefiniowania klasy.
licznik_a.Pokazuj();
licznik_b.Pokazuj(); class Licznik
licznik_c.Pokazuj(); {
public:
} char moja_litera;
int ile;
Licznik::Licznik(char z) Licznik(char litera);
{ void Skok_licznika();
moja_litera = z; };
ile = 0;
98
W programie głównym mo emy zastosowa konstruktor do /* Prototypy funkcji (dwie wersje): ---------------- */
zainicjowania obiektu np. tak:
void Pokazuj1(Licznik);
main()
{ int Pokazuj2(Licznik);
Licznik licznik_a('a');
...
void main()
Zdefiniujmy funkcj . Obiekt licznik_a b dzie argumentem funkcji {
Pokazuj(). Funkcja powinna wyprowadzi na ekran zawarto pola /* inicjujemy licznik: -------------------------------*/
licznik_a.ile. Deklaracja - prototyp takiej pobieraj cej obiekt
funkcji b dzie wygl da tak: Licznik licznik_a('a');
Nazwa klasy spełnia dokładnie tak sam rol jak ka dy inny typ cout << "Wpisz ciag zankow zakonczony kropka [.]" << '\n';
danych. W naszym przypadku b dzie to wygl da tak: for(;;)
{
void Pokazuj(Licznik obiekt); char znak;
cin >> znak;
Poniewa "obiekt" jest parametrem formalnym i jego nazwa nie if(znak == '.') break;
jest tu istotna, mo emy pomin j w prototypie funkcji (w if (znak == licznik_a.moja_litera) licznik_a.Skok_licznika();
definicji ju nie!) i skróci zapis do postaci: }
Funkcja Pokazuj() otrzyma w momencie wywołania jako swój cout << "Wyswietlam wyniki zliczania litery a: \n";
argument kopi obiektu, któr jako argument formalny funkcji
nazwali my "obiekt". W naszym programie wywołanie tej funkcji Pokazuj1(licznik_a);
b dzie wygl da tak: cout << '\n' << Pokazuj2(licznik_a);
Pokazuj(licznik_a); }
PRINT X REM Wyprowad bie c warto zmiennej X Aby "ksywa" oznaczała t sam zmienn , referencj nale y
INPUT X REM Pobierz warto zmiennej X zainicjowa :
writeln(X); { Wyprowad bie ac warto zmiennej X } Zainicjujemy nasz zmienn "zmienna" i b dziemy robi z ni
readln(X); { Pobierz warto zmiennej X } cokolwiek (np. inkrementowa ). Równocze nie b dziemy sprawdza ,
czy odwołania do zmiennej przy pomocy nazwy i referencji b d
przyjmuje w C/C++ form zapisu wyra nie dualnego: pozostawa równowa ne.
danych i umieszczenie ich pod wła ciwym adresem pami ci) jest cout << '\n' << "Zmienna" << " Ksywa";
inaczej. Funkcji zupełnie nie interesuje bie ca wart zmiennej cout << '\n' << zmienna << '\t' << ksywa;
X, jest jej natomiast do poprawnego działania potrzebny adres for (register int i = 0; i < 5; i++, zmienna += 100)
zarezerwowany dla zmiennej X w pami ci. Ale tu okazuje si , e cout << '\n' << zmienna << '\t' << ksywa;
Basic i Pascal post puj dokładnie tak samo, jak poprzednio:
return 0;
INPUT X i read(X); }
Oznacza to, e X nie oznacza dla Pascala i Basica bie cej Dialog (a wła ciwie monolog) powinien wygl da tak:
warto ci zmiennej, lecz oznacza (DOMY LNIE) przekazanie do
funkcji adresu zmiennej X w pami ci. Funkcje oczywi cie C:\>program
"wiedz ", co dostały i dalej ju one same manipuluj danymi we
wła ciwy sposób. Zmienna Ksywa
6666 6666
W C++ jest inaczej. Zapis: 6666 6666
6766 6766
Funkcja(X); 6866 6866
6966 6966
oznacza w praktyce, e zostan wykonane nast puj ce operacje: 7066 7066
* spod adresu pami ci przeznaczonego dla zmiennej X zostanie Referencje i wska niki mo na stosowa a C++ niemal wymiennie
(zgodnie z zadeklarowanym formatem) odczytana bie ca warto (dokładniej - nie jest to wymienno wprost, a uzupełnianie na
zmiennej X; zasadzie odwrotno ci-komplementarno ci).
* warto X zostanie zapisana na stos (PUSH X);
* zostanie wywołana funkcja Funkcja(); [!!!] TO NIE WSZYSTKO JEDNO!.
* Funkcja() pobierze sobie warto argumentu ze stosu (zgodnie z ________________________________________________________________
Mogłoby si wydawa , e operator adresowy & zyskał dwa RÓ NE
formatem zadeklarowanym w prototypie Funkcji()). zastosowania: okre lenie adresu w pam ci oraz tworzenie
* Funkcja() zadziała zgodnie ze swoj definicj i je li ma co wskazania. Aby rozró ni te dwie sytuacje zwró uwag na
do pozostawienia (np. return (wynik); ) pozostawi wynik. "gramatyk " zapisu. Je li identyfikator zminnej jest poprzedzony
* funkcja "nie wie", gdzie w pami ci umieszczony był przekazany int &zmienna; /* lub */ int &zmienna = ... ;
jej argument;
* funkcja komunikuje si "ze wiatem zewn trznym" (czyli własnym to zmienn nazywamy "zmienn referencyjn ". Je li natomiast
identyfikator nie został poprzedzony okre leniem typu:
programem, b d funkcj wy szego rz du - wywołuj c ) tylko za
po rednictwem stosu; p = &zmienna;
* funkcja dostaje swoj "kopi " argumentu z którym działa;
* funkcja nie ma wpływu na "oryginał" argumentu, który pozostaje to mówimy wtedy o adresie zmiennej.
Przekazanie argumentu do funkcji poprzez referencj jest w
bez zmian. istocie zbli one do przekazania wska nika do argumentu. Zwró
uwag , e przekazanie wska nika do obiektu mo e zwykle odby si
REFERENCJA - CO TO TAKIEGO ?
szybciej ni sporz dzenie kopii obiektu i przekazanie tej kopii
Zastanówmy si , czym wła ciwie jest referencja zmiennej w C++. do funkcji. Zastosowanie w deklaracji funkcji operatora
Pewne jest, e jest to alternatywny sposób odwołania si do adresowego & pozwala nam stosowa syntaktyk zapisu tak "jak
zmiennej. Zacznijmy od trywialnego przykładu odwołania si do zwykle" - przy przekazaniu przez warto . Je li nie chcemy
tej samej zmiennej maj cej swoj wła ciw nazw "zmienna" i ryzykowa zmian wprowadzonych do oryginalnego parametru
referencj "ksywa". przekazanego funkcji poprzez wskazanie, mo emy zadeklarowa
oryginalny parametr jako stał (kompilator "dopilnuje" i
# include "iostream.h" uniemo liwi zmian warto ci):
100
nazwa_funkcji(const &nazwa_obiektu); [P119.CPP]
________________________________________________________________
# include "ctype.h"
Poprosimy C++ by pokazał nam konkretne fizyczne adresy # include "iostream.h"
skojarzone z identyfikatorami "zmienna" i "ksywa". Operator &
oznacza dla C++ class Licznik
{
&X --> adres w pami ci zmiennej X public:
char moja_litera;
[P112.CPP] int ile;
Licznik(char z) { moja_litera = z; ile = 0; }
/* UWAGA: Program moze potrzebowac modelu wiekszego niz void Skok_licznika(void) { ile++; }
domyslnie ustawiany MODEL SMALL */ };
class Licznik Ka dej funkcji - metodzie zadeklarowanej wewn trz klasy zostaje
{ w momencie wywołania w niejawny sposób (ang. implicitly)
public: przekazany wska nik do obiektu (w stosunku do którego funkcja ma
char moja_litera;
int ile; zadziała ). Pointer wskazuje funkcji w pami ci ten obiekt,
Licznik(char znak) { moja_litera = z; ile = 0; } którego członkiem jest dana funkcja. Bez istnienia takiego
void Skok_licznika(void) { ile++; } wła nie wska nika nie mogliby my stosowa spokojnie funkcji, nie
};
mogliby my odwoływa si do pola obiektu, gdyby my nie wiedzieli
Aby w programie mo na było odwoła si do obiektu nie poprzez
nazw a przy pomocy wska nika, zadeklarujemy wska nik do jednoznacznie, o który obiekt chodzi. Program posługuje si
obiektów klasy Licznik: automatycznie niejawnym wska nikiem do obiektu (ang. implicit
pointer). Mo emy wykorzysta ten istniej cy, cho do tej pory
Licznik *p; nie widoczny dla nas pointer posługuj c si słowem kluczowym
this (ten). This pointer wskazuje na obiekt, do którego nale y
Wska nik w programie mo emy zastosowa np. tak: funkcja. Korzystaj c z tego wska nika funkcja mo e bez cienia
w tpliwo ci zidentyfikowa wła nie ten obiekt, z którym pracuje
p->Skok_licznika(); a nie obiekt przypadkowy.
(czytaj: Wywołaj metod "Skok_licznika()" w stosunku do obiektu [!!!] FUNKCJE KATEGORII static NIE OTRZYMUJ POINTERA this.
wskazywanego w danym momencie przez wska nik p) Nale y pami ta , e wska nik this istnieje wył cznie podczas
wykonywania metod (ang. class member function execution), za
Trzeba pami ta , e sama deklaracja w przypadku referencji i wyj tkiem funkcji statycznych.
wska ników nie wystarcza. Przed u yciem nale y jeszcze
zainicjowa wska nik w taki sposób, by wskazywał na nasz Je li w programie zadeklarujemy klas Klasa:
obiekt-licznik. Wska nik do obiektu inicjujemy w taki sam sposób
class Klasa
jak ka dy inny pointer: {
int dane;
p = &Obiekt; ...
}
Mo emy przyst pi do utworzenia programu przykładowego.
101
a wewn trz tej klasy metod Pokazuj():
a inaczej liczb całkowitych rzeczywistych. Dlatego te wykonanie
class Klasa
{ operacji mno enia wymaga od operatora * podj cia ró nych
int dane; działa :
public:
void Pokazuj(); class Liczba_zespolona x, y, z; z = x * y;
...
} int x, y, z; z = x * y;
To zdefiniowanie funkcji Pokazuj() z zastosowaniem pointera this Pójd my w tym rozumowaniu o krok dalej. Skoro rozszerzenie
obszaru zastosowa jakiego operatora na obiekty nowej
i notacji wska nikowej (p->), jak poni ej, b dzie równowa ne: (nieznanej wcze niej klasy) wymaga zdefiniowania nowego
algorytmu działania operatora, C++ b dzie potrzebował do tego
void Klasa::Pokazuj(void) celu specjalnych rodków, które powinny by łatwo rozpoznawalne.
{
cout << this->dane; Do opisu algorytmów słu generalnie w C++ funkcje i tu Autorzy
} nie wprowadzili wyj tku. Zastrzegli jednak dla tych specjalnych
funkcji specjaln nazw : operator ...();
Przypomnijmy, e taka notacja wska nikowa oznacza:
"Wyprowad zawarto pola "dane" obiektu, na który wskazuje I tak funkcja precyzuj ca nowy algorytm dodawania (nowy sposób
wska nik" (poniewa jest to wska nik this, wi c chodzi o własny działania operatora + ) b dzie si nazywa :
obiekt).
operator+();
a np. funkcja okre laj ca nowy algorytm mno enia (nowy sposób
LEKCJA 34 OVERLOADING OPERATORÓW. działania operatora * ) b dzie si nazywa :
________________________________________________________________
Podczas tej lekcji poznasz mo liwo ci dostosowania operatorów operator*();
C++ do własnego "widzimisi " i do potrzeb własnych obiektów.
________________________________________________________________ Spróbujmy zastosowa tak filozofi w praktyce programowania.
Niemal od pocz tku niniejszej ksi ki korzystamy z operatorów [!!!] NIESTETY NIE WSZYSTKIE OPERATORY MO NA
poddanych overloadingowi. S to operatory << i >> , które ROZBUDOWA .
pierwotnie wykonywały bitowe przesuni cie w lewo i w prawo. ________________________________________________________________
Owerloading tych operatorów "załatwił" za nas producent S w C++ operatory, których nie mo emy podda overloadingowi. S
(Borland, Microsoft, czy inny). Jak widzisz, nie powoduje to w
dalszym u ytkowaniu tych operatorów adnych zauwa alnych to:
komplikacji, a cz sto ułatwia tworzenie programów. Zwró uwag ,
e overloading operatorów (jak i definicje klas) mo e znajdowa . :: .* ?:
si w doł czonych plikach nagłówkowych i po jednorazowym
wykonaniu mo e by "niewidoczny" dla programistów tworz cych . operator kropki umo liwia dost p do pól struktur i obiektów;
programy aplikacyjne.
:: operator "widoczno ci-przesłaniania" (ang. scope);
Je li projektujemy (definiujemy) now klas , dodajemy do C++ .* wskazanie członka klasy (ang. pointer-to-member);
nowy, lecz pełnoprawny typ danych. Autorzy C++ nie byli w stanie ?: operator warunkowy.
________________________________________________________________
przewidzie jakie klasy i jakie obiekty mog wymy li kolejne
pokolenia programistów w ramach swojej radosnej twórczo ci. Wszystkie pozostałe operatory mo emy podda overloadingowi i
Wprowadzili zatem do C++ jasne i jednoznaczne algorytmy przypisywa im potrzebne nam działanie.
post powania z typami "typowymi". C++ doskonale wie jak dodawa ,
OVERLOADING OPERATORA [+] (DWUARGUMENTOWEGO).
mno y , czy odejmowa np. liczby int, long, float itp., nie wie
jednak jak doda do siebie obiekty klas CString (CString = Class Zaczniemy od operatora + nale cego do grupy "dwuargumentowych
operatorów arytmetycznych" (ang. binary arithmetic operator).
String = klasa "ła cuch znaków"), TOdcinek (to taki kawałek Zwracamy tu ju na pocz tku rozwa a uwag na przynale no
prostej) itp.. A przecie miło byłoby, gdyby rozbudowa operatora do okre lonej grupy, poniewa overloading ró nych
działanie operatorów tak, by było mo liwe ich typowe opertorów nale cych do tej samej grupy przebiega podobnie.
zastosowanie w stosunku do naszych własnych, "nietypowych" Poniewa znak + mo e by tak e operatorem jednoargumentowym
obiektów: (ang. unary plus, o czym za chwil ), podkre lamy, e tym razem
chodzi o plus jako operator dodawania. Overloading operatora
int x, y; int z = x + y; //To operator + załatwia sam przeprowadzimy w stosunku do obiektów prostej, znanej Ci ju z
float x, y; float z = x + y; poprzednich przykładów klasy Data, któr (w celu upodobnienia
si do maniery stosowanej w Windows i bibliotekach klas)
Zanim jednak stanie si mo liwe post powanie takie: nazwiemy tym razem CData. "Namówimy" operator + do
przeprowadzenia operacji na obiektach (dokładniej na polach
class CString x, y, z; z = x + y; obiektów):
class Nasza_Klasa obiekt1, obiekt2, obiekt3; CData nowadata = staradata + 7; // W tydzien pozniej
obiekt3 = obiekt1 + obiekt2;
Operator + musi oczywi cie "wiedzie ", na którym polu obiekty
itp., itd. ... klasy CData przechowuj liczb dni i jak zwi zane s (logicznie)
musimy "uzupełni " C++ i "wyja ni " operatorom, co wła ciwie ma pola obiektu dz, mc, rok. Jest rzecz zrozumiał , e samo
w praktyce oznacza operacja obiekt1 = obiekt2 + obiekt3; . dodanie dni do pola dz mo e nie wystarczy , poniewa data
Jest wyczuwalne intuicyjnie, e działanie operatorów w stosunku 37.11.93 jest niedopuszczalna.
do ró nych obiektów mo e by ró ne. Dla przykładu - wiesz
zapewne, e inaczej wygl da algorytm mno enia liczb zespolonych, Je li staradata jest obiektem klasy CData z zawartymi wewn trz
102
danymi, to w wyniku działania "nowego" operatora + powinien W prawym polu operatora (operator jest dwuargumentowy, ma wi c
powsta obiekt nowadata klasy CData, którego pola zostan w swoje lewe i prawe pole) mo e pojawi tak e stała. Operacja:
sensowny sposób powi kszone o dodan liczb dni. Rozwa
działanie programu (najlepiej skompiluj i uruchom). nowadata = staradata + 14;
/* Overloading operatora dwuargumentowego + */ Ale to nie wszystko. Je li wyst pi układ odwrotny - np.:
to zostanie tu wykorzystany operator + rozbudowany poprzednio [!!!] Mo esz dodawa obiekty minusem.
przez metod CData::operator+(int). Program w cało ci mo e ________________________________________________________________
zatem wygl da tak: * Nale y tu zwróci uwag , e dodawanie obiektów mo e wykonywa
nie tylko i nie koniecznie operator + . Je li zechcesz, mo esz
[P121.CPP] do tego celu zastosowa dowolnie wybrany operator (np. -, *
itp.). W celu ułatwienia zrozumienia zapisu (i tylko dlatego)
# include "iostream.h" wi kszo programistów rozbudowuje działanie operatorów zgodnie
z ich pierwotnym zastosowaniem.
class CData * DOWOLNO , ALE NIE PEŁNA!
{ O tyle, o ile działanie operatora mo e by zmienione, to ilo
int dz, mc, rok; argumentów potrzebnych operatorowi pozostaje w C++ "sztywna"
public: (patrz przykład z n!).
CData() {} ________________________________________________________________
CData(int d, int m, int y) { mc = m; dz = d; rok = y; }
void Pokazuj() { cout << dz << '.' << mc << '.' << rok; } W bardzo podobny sposób mo esz rozbudowywa inne arytmetyczne
CData operator+(int); operatory dwuargumentowe (*, /, -, itp.) w stosunku tak e do
friend CData operator+(int n, CData& x) { return (x + n); } innych klas.
};
OVERLOADING OPERATORÓW JEDNOARGUMENTOWYCH ++ I -- .
static int TAB[] = {31,28,31,30,31,30,31,31,30,31,30,31};
Typowe operatory jednoargumentowe to ++ i --. Jako przykładem
CData CData::operator+(int n) posłu ymy si problemem zlicznia znaków pobieranych ze
{ strumienia wej ciowego.
CData kopia_obiektu = *this;
n += kopia_obiektu.dz; Zaczniemy od redefinicji postinkrementacji licznika. Musimy
while (n > TAB[kopia_obiektu.mc-1]) zastosowa funkcj operatorow . Funkcja, chc c operowa na
{ obiektach musi w stosunku do tych obiektów posiada status
n -= TAB[kopia_obiektu.mc-1]; friend, lub by metod . Prototyp funkcji operatorowej potrzebnej
if (++kopia_obiektu.mc == 13)
{ kopia_obiektu.mc = 1; kopia_obiektu.rok++; } do wykonania overloadingu operatora jednoargumentowego ++
} wygl da w postaci ogólnej tak:
kopia_obiektu.dz = n;
return (kopia_obiektu); typ_zwracany nazwa_klasy::operator++(lista argumentów);
}
Funkcje operatorowe zwracaj zwykle warto zgodn co do typu z
main() typem obiektów z którymi współpracuj . Je li identyfikatory b, c
{
CData staradata(31, 1, 94); //Kostruktor z argumentami i d reprezentuj obiekty, nic nie stoi na przeszkodzie, by stał
CData nowadata, jeszczejednadata; si mo liwy zapis:
cout << "\n Stara data: ";
staradata.Pokazuj(); class Klasa
cout << "\n Podaj ile minelo dni --> "; {
int n; ...
cin >> n; } x, y, z;
nowadata = staradata + n; ...
cout << "\n Jest zatem --> "; z = x + y;
nowadata.Pokazuj();
cout << "\n Testuje nowy operator: "; Dodajemy dwa obiekty x i y tego samego typu (tej samej klasy), a
jeszczejednadata = (1+n) + staradata;
jeszczejednadata.Pokazuj(); wynik przypisujemy obiektowi z, który tak e jest obiektem tego
return 0; samego typu. Je li mo naby jeszcze zastosowa operator
} przypisania tak:
int x; [P126.CPP]
Dzi ki dziedziczeniu programista mo e w pełni wykorzysta gotowe Cpochodna::Cpochodna(char c1,char c2,char c3) : CBazowa1(c2),
CBazowa2(c3)
biblioteki klas, tworz c własne klasy i obiekty, jako klasy {
pochodne wazgl dem "fabrycznych" klas bazowych. Je li bazowy cout << c1;
zestw danych i funkcji nie jest adekwatny do potrzeb, mo na np. }
przesłoni , rozbudowa , b d przebudowa bazow metod dzi ki
elastyczno ci C++. Zdecydowana wi kszo standardowych klas Konstruktor klasy pochodnej pobiera trzy argumenty i dwa z nich:
bazowych wyposa ana jest w konstruktory. Tworz c klas pochodn
powinni my pami ta o istnieniu konstruktorów i rozumie sposoby c2 --> przekazuje do konstruktora klasy CBazowa1
c3 --> przekazuje do konstruktora klasy CBazowa2
przekazywania argumentów obowi zuj ce konstruktory w przypadku Sposób zapisu w C++ wygl da tak:
bardziej zło onej struktury klas bazowych-pochodnych.
Cpochodna::Cpochodna(char c1,char c2,char c3) : CBazowa1(c2),
PRZEKAZANIE PARAMETRÓW DO WIELU KONSTRUKTORÓW. CBazowa2(c3)
Klasy bazowe mog by wyposa one w kilka wersji konstruktora. Mo emy zatem przekaza parametry "w tył" do konstruktorów klas
Dopóki nie przeka emy konstruktorowi klasy bazowej adnych bazowych w taki sposób:
argumentów - zostanie wywołany (domy lny) pusty konstruktor i
klasa bazowa b dzie utworzona z parametrami domy lnymi. Nie kl_pochodna::kl_pochodna(lista):baza1(lista), baza2(lista), ...
zawsze jest to dla nas najwygodniejsza sytuacja.
gdzie:
Je eli wszystkie, b d cho by niektóre z parametrów, które lista - oznacza list parametrów odpowiedniego konstruktora.
przekazujemy konstruktorowi obiektu klasy pochodnej powinny
zosta przekazane tak e konstruktorowi (konstruktorom) klas W takiej sytuacji na li cie argumentów konstruktorów klas
bazowych, powinni my wytłumaczy to C++. Z tego te powodu, bazowych mog znajdowa si tak e wyra enia, przy zało eniu, e
je li konstruktor jakiej klasy ma jeden, b d wi cej elementy tych wyra e s widoczne i dost pne (np. globalne
parametrów, to wszystkie klasy pochodne wzgl dem tej klasy stałe, globalne zmienne, dynamicznie inicjowane zmienne globalne
bazowej musz posiada konstruktory. Dla przykładu dodajmy
konstruktor do naszej klasy pochodnej Cpochodna: itp.). Konstruktory b d wykonywane w kolejno ci:
class Cpochodna : public CBazowa1, CBazowa2 //Lista klas tym na przykładzie. Zacznijmy od zadeklarowania funkcji
{ wirtualnej (przy pomocy słowa kluczowego virtual) w klasie
public: bazowej. Zadeklarujemy jako funkcj wirtualn funkcj oddychaj()
Cpochodna(...); //Konstruktor
}; w klasie CZwierzak:
class CPiesek : public CZwierzak Taki efekt nazywa si polimorfizmem uruchomieniowym (ang.
{ run-time polymorphism).
char imie[30];
} Ciapek; Overloading funkcji i operatorów daje efekt tzw. polimorfizmu
kompilacji (ang. compile-time), to funkcje wirtualne daj efekt
class CRybka polimorfizmu uruchomieniowego (run-time). Poniewa wszystkie
char imie[30]; wersje funkcji wirtualnej maj taki sam prototyp, nie ma innej
public: metody stwierdzenia, któr wersj funkcji nale y zastosowa .
void Oddychaj() {cout << "\nSardynka: A ja nie oddycham.";} Wybór wła ciwej wersji funkcji mo e by dokonany tylko na
} Sardynka; podstawie typu obiektu, do którego nale y wersja funkcji-metody.
Funkcja CZwierzak::Oddychaj() została w obiekcie Sardynka wczesnego polimorfizmu (compile-time, early binding) C++ wybiera
przesłoni ta przez funkcj CRybka::Oddychaj() - nowsz wersj
funkcji-metody pochodz c z klasy pochodnej. wersj funkcji (poddanej overloadingowi) do zastosowania ju
tworz c plik .OBJ. W przypadku pó nego polimorfizmu (run-time,
Overloading funkcji zasadzał si na "typologicznym pedanty mie" late binding) C++ wybiera wersj funkcji (poddanej przesłanianiu
C++ i na dodatkowych informacjach, które C++ doł cza przy
kompilacji do funkcji, a które dotycz licznby i typów - overriding) do zastosowania po sprawdzeniu bie cego kontekstu
argumentów danej wersji funkcji. W przypadku funkcji wirtualnych
i zgodnie z bie cym wskazaniem pointera.
jest inaczej. Aby wykona przesłanianie kolejnych wersji funkcji
Przyjrzyjmy si dokładniej zastosowaniu wska ników do obiektów w
wirtualnej w taki sposób, funkcja we wszystkich "pokoleniach"
musi mie taki sam prototyp, tj. pobiera tak sam liczb przykładowym programie. Utworzymy hierarchi zło on z klasy
parametrów tych samych typów oraz zwraca warto tego samego bazowej i pochodnej w taki sposób, by klasa pochodna zawierała
typu. Je li tak si nie stanie, C++ potraktuje ró ne prototypy jaki unikalny element - np. nie wyst puj c w klasie bazowej
tej samej funkcji w kolejnych pokoleniach zgodnie z zasadami funkcj .
overloadingu funkcji. Zwró my tu uwag , e w przypadku funkcji
wirtualnych o wyborze wersji funkcji decyduje to, wobec którego class CZwierzak
obiektu (której klasy) funkcja została wywołana. Je li wywołamy {
funkcj dla obiektu Ciapek, C++ wybierze wersj public:
CZwierzak::Oddychaj(), natomiast wobec obiektu Sardynka zostanie void Jedz();
virtual void Oddychaj() {cout << "\nSapie...";}
zastosowana wersja CRybka::Oddychaj(). };
W C++ wska nik do klasy bazowej mo e tak e wskazywa na klasy class CPiesek : public CZwierzak
pochodne, wi c zastosowanie funkcji wirtualnych mo e da pewne {
ciekawe efekty "uboczne". Je li zadeklarujemy wska nik *p do char imie[20];
obiektów klasy bazowej CZwierzak *p; a nast pnie zastosujemy ten void Szczekaj() { cout << "Szczekam !!!"; }
} Ciapek;
sam wska nik do wskazania na obiekt klasy pochodnej:
Je li teraz zadeklarujemy wska nik do obiektów klasy bazowej:
p = &Ciapek; p->Oddychaj();
... CZwierzak *p;
p = &Sardynka; p->Oddychaj();
to przy pomocy tego wska nika mo emy odwoła si tak e do
zarz damy w taki sposób od C++ rozpoznania wła ciwej wersji obiektów klasy pochodnej oraz do elementów obiektu klasy
wirtualnej metody Oddychaj() i jej wywołania we wła ciwym pochodnej - np. do funkcji p->Oddychaj(). Ale pojawia si tu
momencie. C++ mo e rozpozna , któr wersj funkcji nale ałoby pewien problem. Je li zechceliby my wskaza przy pomocy pointera
zastosowa tylko na podstawie typu obiektu, wobec którego
funkcja została wywołana. I tu pojawia si pewien problem. taki element klasy pochodnej, który nie został odziedziczony i
Kompilator wykonuj c kompilcj programu nie wie, co b dzie którego nie ma w klasie bazowej? Rozwi zanie jest proste -
wskazywał pointer. Ustawienie pointera na konkretny adres wystarczy zarz da od C++, by chwilowo zmienił typ wska nika z
nast pi dopiero w czasie wykonania programu (run-time). obiektów klasy bazowej na obiekty klasy pochodnej. W przypadku
Kompilator "wie" zatem tylko tyle: funkcji Szczekaj() w naszym programie wygl dałoby to tak:
108
public:
CZwierzak *p; virtual void Oddychaj() = 0;
... ...
p->Oddychaj(); };
p->Szczekaj(); // LE !
(CPiesek*)p->Szczekaj(); //Poprawnie class CPiesek : public CZwierzak
... {
...
Dzi ki funkcjom wirtualnym tworz c klasy bazowe pozwalamy public:
pó niejszym u ytkownikom na rozbudow funkcji-metod w void Oddychaj() { cout << "Oddycham..."; }
najwła ciwszy ich zdaniem sposób. Dzi ki tej "nieokre lono ci" ...
dziedzicz c mo emy przejmowa z klasy bazowej tylko to, co nam };
odpowiada. Funkcje w C++ mog by jeszcze bardziej
"nieokre lone" i rozbudowywalne. Nazywaj si wtedy funkcjami w Przykładem takiej funkcji jest funkcja Mów() z przedstawionego
pełni wirtualnymi. poni ej programu. Zostawiamy j w pełni wirtualn , poniewa
LEKCJA 36: FUNKCJE WIRTUALNE i KLASY ABSTRAKCYJNE. ró ne obiekty klasy CZLOWIEK i klas pochodnych
________________________________________________________________
W trakcie tej lekcji dowiesz si , co mawia ona programisty, gdy class CZLOWIEK
{
nie chce by obiektem klasy abstrakcyjnej. public:
________________________________________________________________ void Jedz(void);
virtual void Mow(void) = 0; //funkcja WIRTUALNA
FUNKCJE W PEŁNI WIRTUALNE (PURE VIRTUAL). };
W skrajnych przypadkach wolno nam umie ci funkcj wirtualn w class NIEMOWLE : public CZLOWIEK
klasie bazowej nie definiuj c jej wcale. W klasie bazowej {
umieszczamy wtedy tylko deklaracj -prototyp funkcji. W public:
nast pnych pokoleniach klas pochodnych mamy wtedy pełn swobod void Mow(void); // Tym razem BEZ slowa virtual
i mo emy zdefiniowa funkcj wirtualn w dowolny sposób - };
adekwatny dla potrzeb danej klasy pochodnej. Mo emy np. do klasy /* Tu definiujemy metod wirtualn : -------------------- */
void NIEMOWLE::Mow(void) { cout << "Nie Umiem Mowic! \n"; };
bazowej (ang. generic class) doda prototyp funkcji wirtualnej
funkcja_eksperymentalna() nie definiuj c jej w (ani wobec)
klasie bazowej. Sens umieszczenia takiej funkcji w klasie mog mówi na ró ne sposoby... Obiekt Niemowle, dla przykładu,
bazowej polege na uzyskaniu pewno ci, i wszystkie klasy nie chce mówi wcale, ale z innymi obiektami mo e by inaczej.
pochodne odziedzicz funkcj funkcja_eksperymentalna(), ale Wyobra sobie np. obiekt klasy ona ( ona to przecie te
ka da z klas pochodnych wyposa y t funkcj we własn definicj . człowiek !).
Takie post powanie mo e okaza si szczególnie uzasadnione przy class Zona : public CZLOWIEK
tworzeniu biblioteki klas (class library) przeznaczonej dla {
innych u ytkowników. C++ w wersji instalacyjnej posiada ju public:
kilka gotowych bibliotek klas. Funkcje wirtuale, które nie void Mow(void);
zostaj zdefiniowane - nie posiadaj zatem ciała funkcji - }
nazywane s funkcjami w pełni wirtualnymi (ang. pure virtual
function). W tym pokoleniu definicja wirtualnej metody Mow() mogłaby
wygl da np. tak:
O KLASACH ABSTRAKCYJNYCH.
void Zona::Mow(void)
Je li zadeklarujemy funkcj CZwierzak::Oddychaj() jako funkcj w {
cout << "JA NIE MAM CO NA SIEBIE WLOZYC !!! ";
pełni wirtualn , oprócz słowa kluczowego virtual, trzeba t cout << "DLACZEGO KOWALSKI ZARABIA ZAWSZE WIECEJ NIZ TY
informacj w jaki sposób przekaza kompilatorowi C++. Aby C++ ?!!!";
wiedział, e nasz intencj jest funkcja w pełni wirtalna, nie
mo emy zadeklarowa jej tak: //... itd., itd., itd...
}
class CZwierzak
{ [P128.CPP]
...
public: #include "iostream.h"
virtual void Oddychaj();
... class CZLOWIEK
}; {
public:
a nast pnie pomin definicj (ciało) funkcji. Takie void Jedz(void);
post powanie C++ uznałby za bł d, a funkcj - za zwykł funkcj virtual void Mow(void) = 0;
wirtualn , tyle, e "niedorobion " przez programist . Nasz };
intencj musimy zaznaczy ju w definicji klasy w taki sposób:
void CZLOWIEK::Jedz(void) { cout << "MNIAM, MNIAM..."; };
class CZwierzak
{ class Zona : public CZLOWIEK
... {
public: public:
virtual void Oddychaj() = 0; void Mow(void); //Zona mowi swoje
... }; //bez wzgledu na argumenty (typ void)
};
void Zona::Mow(void)
Informacj dla kompilatora, e chodzi nam o funkcj w pełni {
wirtualn , jest dodanie po prototypie funkcji "= 0". Definiuj c cout << "JA NIE MAM CO NA SIEBIE WLOZYC !!!";
klas pochodn mo emy rozbudowa funkcj wirtualn np.: cout << "DLACZEGO KOWALSKI ZARABIA ZAWSZE WIECEJ NIZ TY
?!!!";
class CZwierzak
{ }
...
109
class NIEMOWLE : public CZLOWIEK CA obiekt;
{ public:
public: CB() { obiekt = 1; cout << "->Konstruktor CB() "; }
void Mow(void); };
};
Mo emy teraz sprawdzi , co stanie si w programie po
void NIEMOWLE::Mow(void) { cout << "Nie Umiem Mowic! \n"; }; zadeklarowaniu obiektu klasy CB:
main() [P129.CPP]
{
NIEMOWLE Dziecko; # include "iostream.h"
Zona Moja_Zona;
class CA
Dziecko.Jedz(); {
Dziecko.Mow(); int liczba;
Moja_Zona.Mow() public:
CA() { liczba = 0; cout << "-> CA(), CA_O::liczba = 0 "; }
return 0; CA(int x) { liczba = x; cout << "->CA(int) "; }
} void operator=(int n) { liczba = n; cout << "->operator "; }
};
Przykładowa klasa CZŁOWIEK jest klas ABSTRAKCYJN . Je li
spróbujesz doda do powy szego programu np.: class CB
{
CZLOWIEK Facet; CA obiekt;
Facet.Jedz(); public:
CB() { obiekt = 1; cout << "->Konstruktor CB() "; }
uzyskasz komunikat o bł dzie: };
Poniewa wyja nili my, dlaczego klasy s nowymi typami danych, C:\>program
wi c logika (i sens) innej rozpowszechnionej nazwy klas -> CA(), CA_O::liczba = 0 ->operator ->Konstruktor CB()
abstrakcyjnych - ADT - Abstract Data Type (Abstrakcyjne Typy
Danych) jest chyba zrozumiała i oczywista. Skoro oprócz zainicjowania obiektu klasy pochodnej nie robimy w
programie dokładnie nic, nie dziwmy si ostrze eniu
ZAGNIE D ANIE KLAS I OBIEKTÓW.
Warning: Obiekt is never used...
Mo e si np. zdarzy , e klasa stanie si wewn trznym elementem
(ang. member) innej klasy i odpowiednio - obiekt - elementem Jest to sytuacja troch podobna do komunikacji pomi dzy
innego obiektu. Nazywa si to fachowo "zagnie d aniem" (ang. konstruktorami klas bazowych i pochodnych. Je li zaprojektujemy
nesting). Je li, dla przykładu klasa CB b dzie zawiera obiekt prost struktur klas:
klasy CA:
class CBazowa
class CA {
{ private:
int liczba; int liczba;
public: public:
CA() { liczba = 0; } //Konstruktor domyslny CBazowa() { liczba = 0}
CA(int x) { liczba = x; } CBazowa(int n) { liczba = n; }
void operator=(int n) { liczba = n } };
};
class CPochodna : public CBazowa
class CB {
{ public:
CA obiekt; CPochodna() { liczba = 0; }
public: CPochodna(int x) { liczba = x; }
CB() { obiekt = 1; } };
};
problem przekazywania parametrów mi dzy konstruktorami klas
Nasze klasy wyposa yli my w konstruktory i od razu poddali my mo emy w C++ rozstrzygn i tak:
overloadingowi operator przypisania = . Aby prze ledzi
kolejno wywoływania funkcji i sposób przekazywania parametrów class CPochodna : public CBazowa
pomi dzy tak powi zanymi obiektami rozbudujemy ka d funkcj o {
zgłoszenie na ekranie. public:
CPochodna() : CBazowa(0) { liczba = 0; }
class CA CPochodna(int x) { liczba = x; }
{ };
int liczba;
public: B dzie to w praktyce oznacza wywołanie konstruktora klasy
CA() { liczba = 0; cout << "-> CA(), CA_O::liczba = 0 "; } bazowej z przekazanym mu argumentem 0. Podobnie mo emy post pi
CA(int x) { liczba = x; cout << "->CA(int) "; } w stosunku do klas zagnie d onych:
void operator=(int n) { liczba = n; cout << "->operator "; }
}; [P130.CPP]
Eksperymentuj c z dwoma powy szymi programami mo esz przekona Truizmy u yte w tytule maj znaczy , e "zasoby najlepszego
si , jak przebiega przekazywanie parametrów pomi dzy nawet komputera s ograniczone" i zwykle okazuj si
konstruktorami i obiektami klas bazowych i pochodnych. wystarczaj ce tylko do pewnego momentu. Najbardziej newralgiczne
Szczególnie wa nym wska nikiem przy tworzeniu klas pochodnych i * czas mikroprocesora i
funkcji operatorowych mo e okaza si pointer *this. Oto * miejsce w pami ci operacyjnej.
przykład listy.
Tworzone przez nas programy powinny wystrzega si zatem
[P131.CPP] najci szych grzechów:
*dp - data pointer - wska nik do danych (near/far) /* Funkcja sprawdza stan klawiszy specjalnych --------- */
*cp - code pointer - wska nik do kodu.
Large - kod + dane = max. 1 MB. modyfikatory = bioskey(2);
Huge - kod = max. 1 MB, wiele segmentów danych po 64 K ka dy. if (modyfikatory)
{
Wynikaj ce z takich modeli pami ci kwalifikatory near, far, huge printf("\n");
if (modyfikatory & RIGHT) printf("RIGHT");
dotycz ce pointerów w C++ nie s akceptowane przez standard ANSI if (modyfikatory & LEFT) printf("LEFT");
if (modyfikatory & CTRL) printf("CTRL");
C (poniewa odnosz si tylko do IBM PC i nie maj charakteru if (modyfikatory & ALT) printf("ALT");
uniwersalnego). Trzeba tu zaznaczy , e typ wska nika jest przez printf("\n");
}
kompilator przyjmowany domy lnie (automatycznie) zgodnie z /* drukujemy pobrany klawisz */
wybranym do kompilacji modelem pami ci. Je li poruszamy si if (isalnum(klawisz & 0xFF))
wewn trz niewielkiego obszaru pami ci, mo esz "forsowa " bli szy printf("'%c'\n", klawisz);
else
typ pointera, przyspieszaj c tym samym działanie programów: printf("%#02x\n", klawisz);
}
huge *p;
... Nale y tu zwróci uwag , e funkcje kbhit() i bioskey() nie
near *ptr; //Bliski pointer dokonuj czyszczenia bufora klawiatury. Identyfikuj znak
... (znaki) w buforze, ale pozostawiaj bufor w stanie niezmienionym
near int Funkcja(...) //Bliska funkcja
{ do dalszej obróbki. Zwró uwag , e funkcja getch() mo e
... oczekiwa na klawisz w niesko czono . Sprawdzi szybciej, czy
} u ytkownik nacisn ł ju cokolwiek mo esz np. tak:
#define ILE (1024*640)
if (kbhit()) ...; if (!kbhit()) ...;
near unsigned int Funkcja(void)
{ while (!bioskey(1)) ... if (bioskey(1)) ...;
huge char *ptr; // tu długi pointer jest niezb dny
long suma = 0; Inn wielce przydatn "szybk " funkcj jest getch(). Oto
for (p = 0; p < ILE; p++) suma += *p; praktyczny przykład pobierania i testowania naci ni tych
return (suma); klawiszy klawiatury.
}
[P131.CPP]
Zarówno zadeklarowanie funkcji jako bliskiej (near), jak i jako
statycznej (static) powoduje wygenerowanie uproszczonej # include "stdio.h"
sekwencji wywołania funkcji przez kompilator. Daje to w efekcie # include "conio.h"
mniejszy i szybszy kod wynikowy.
char z1, z2;
IDENTYFIKACJA KLAWISZY.
void Odczyt(void)
Znane Ci z pliku <stdio.h> i <conio.h> "klasyczne" funkcje {
obsługi konsoli maj pewne zalety. Korzystanie z klasycznych, z2 = '\0';
nieobiektowych mechanizmów powoduje z reguły wygenerowanie z1 = getch();
znacznie krótszego kodu wynikowego. Funkcje scanf() i gets() if (z1 == '\0') z2 = getch();
wymagaj wci ni cia klawisza [Enter]. Dla szybkiego dialogu z }
komputerem znacznie bardziej nadaj si szybsze getch() i
kbhit(). Poniewa klawiatura zawiera tak e klawisze specjalne main()
(F1 ... F10, [Shift], [Del], itp.), pełn informacj o stanie {
klawiatury mo na uzyska za po rednictwem funkcji bioskey(), clrscr();
korzystaj cej z przerywania BIOS Nr 16. Oto krótki przykład printf("\nKropka [.] = Quit");
zastosowania funkcji bioskey(): printf("\nRozpoznaje klawisze [F1] ... [F3] \n\n");
Wyprowadzanie znaków na ekran mo na przeprowadzi szybciej Nawet odkr cenie małej rubki bywa niezwykle trudne, gdy do
posługuj c si przerywaniem DOS INT 29H. Drukowanie na ekranie w dyspozycji mamy tylko młotek... Napisanie aplikacji okienkowej
przy pomocy Turbo Pascal 6, Turbo C, Quick C, czy QBASIC
trybie tekstowym przebiega wtedy szybciej ni robi to rzeczywi cie BYŁO nadwyraz trudne.
standardowe funkcje <stdio.h>, <conio.h>, czy <iostream.h>.
Poni ej prosty przykład praktyczny wykorzystania przerywania I tu wła nie dochodzimy do sedna sprawy:
29H:
(!!!) Programowanie dla Windows BYŁO trudne (!!!)
[P132.CPP]
zestawienie plików pomocniczych zawiera tabela poni ej. PIERWSZA APLIKACJA "specjalnie dla Windows".
Najwa niejsze pliki pomocnicze w kompilatorach Borland/Turbo Tryb post powania z kompilatorem BORLAND C++ 3.0/3.1 b dzie w
C++. tym przypadku dokładnie taki sam, jak np. z Turbo Pascalem.
________________________________________________________________ Wszystkich niezb dnych zmian w konfiguracji kompilatora ju
dokonali my. Kompilator "wie" ju , e chcemy uzyska w efekcie
Rozszerzenie Przeznaczenie Gdzie/Uwagi aplikacj dla Windows w postaci programu .EXE. Mo emy zatem
________________________________________________________________
* Wyda rozkaz File | New
.C .CPP Teksty ródłowe \EXAMPLES \SOURCE
(ASCII) (przykłady) (kod ródł.) Pojawi si nowe okienko robocze. Zwró uwag , e domy lne
.H .HPP .CAS Pliki nagłówkowe \INCLUDE rozszerzenie jest .CPP, co powoduje domy lne zastosowanie
(ASCII) kompilatora C++ (a nie kompilatora C - jak w przypadku plików z
.PRJ .DPR .IDE Projekty \EXAMPLES \SOURCE rozszerzeniem .C). Mo esz to oczywi cie zmieni , je li zechcesz,
.TAH .TCH .TDH Help posługuj c si menu Options | Compiler | C++ options... (Opcje |
.TFH .HLP .HPJ
.RTF Kompilator | Kompilator C albo C++). W tym okienku dialogowym
masz sekcj :
.DSK .TC .CFG Konfiguracyjne
.DSW .BCW Use C++ Compiler: Zastosuj Kompilator C++
(zamiast kompilatora C)
.DEF .RC .RES Zasoby i definicje (.) CPP extention - tylko dla rozszerzenia .CPP
.RH .ICO .BMP ( ) C++ always - zawsze
.BGI .CHR .RTF Grafika DOS, fonty * Wybierz rozkaz Save as... z menu File
.MAK .NMK .GEN Pliki instrukta owe dla Pojawi si okienko dialogowe "Save File As" (zapis pliku pod
MAKEFILE MAKE.EXE wybran nazw i w wybranym miejscu).
.ASM .INC .ASI Do asemblacji (ASCII) * Do okienka edycyjnego wpisz nazw pliku i pełn cie k
dost pu - np. A:\WIN1.CPP lub C:\C-BELFER\WIN1.CPP
.RSP Instrukta owy dla TLINK
Zmieni si tytuł roboczego okna z NONAME00 na wybran nazw
.LIB .DLL Biblioteki
Mo emy wpisa tekst pierwszego programu:
.TOK Lista słów zastrze onych (reserved words)
(ASCII) [P133.CPP]
.DRV Sterowniki (drivery)
#include <iostream.h>
.OVL Nakładki (overlay)
void main()
.SYM Plik ze skompilowanymi (Pre - compiled) {
plikami nagłówkowymi. cout << " Pierwsza Aplikacja " << " Dla MS Windows ";
________________________________________________________________ }
Je li w IDE wersji kompilatora przeznaczonej dla rodowiska DOS Je li nie pisałe jeszcze programów dla Windows - mo esz by
spróbujesz uruchomi program WIN1.EXE w tradycyjny sposób - troch zaskoczony. Gdzie w naszym programie jest napisane np. -
rozkazem Run z menu Run - na ekranie pojawi si okienko z co powinno znale si w menu??? Odpowied jest prosta -
komunikatem o bł dzie (Error message box): nigdzie. Podobnie jak programy tworzone dla DOS korzystaj w
niejawny sposób z zasobów systemu - standardowych funkcji DOS,
Can't run a Windows EXE file standardowych funkcji BIOS, przerywa , itp - tak programy
D:\WIN1.EXE tworzone dla Windows mog w niejawny sposób korzysta z zasobów
rodowiska Windows - standardowego menu, standardowych okien,
[ OK ] standardowych klawiszy, itp.. Takie zasoby udost pniane przez
rodowisko programom aplikacyjnym nazywaj si interfejsem API
czyli: "Nie mog uruchomi pliku EXE dla Windows". (Application Program Interface). Poznałe ju API DOS'a - jego
przerywania i funkcje. Interfejs Windows nazywa si "Windows
Jak ju napisałem wcze niej, kompilatory C++ w pakietach 3.0/3.1 API" i to z jego gotowych funkcji wła nie korzystamy.
maj swoje ulubione specjalno ci: Uruchom program wielokrotnie (min. 4 razy). Wykonaj 4 - 6 razy
czynno ci oznaczone powy ej trzema gwiazdkami *** . Poniewa nie
Borland C++ - jest zorientowany na współprac z DOS
Turbo C++ - jest zorientowany na współprac z Windows za dali my, by okno programu było zawsze "na wierzchu" (on top)
Wyjd z IDE BC/BCW. (patrz rys. poni ej). Na rysunkach poni ej przedstawiono kolejne
Z poziomu Mened era Programów mo esz uruchomi swój program stadia pracy z nasz PIERWSZ APLIKACJ .
rozkazem Plik | Uruchom. Do okienka musisz oczywi cie wpisa
poprawn cie k do pliku WIN1.EXE (czyli katalog wyj ciowy Aplikacja WIN1.EXE została wyposa ona w ikonk systemow (znane
kompilatora Borland C++). Ci okienko). Ikonka jest transparentna (półprzezroczysta) i
mo emy j tak e metod drag and drop przenie w dowolne miejsce
*** Wybierz z menu głównego Mened era Programów (pasek w górnej
cz ci ekranu) rozkaz Plik. Rozwinie si menu Plik. - np. do roboczego okna naszej aplikacji. Zwró uwag tak e na
*** Wybierz z menu Plik rozkaz Uruchom. Pojawi si okienko towarzysz cy nazwie programu napis "inactive" (nieaktywna).
dialogowe uruchamiania programów. Wpisz pełn cie k Chodzi o to, e program zrobił ju wszystko, co miał do
dost pu do programu - np.: zrobienia i zako czył si . DOS doło yłby standardowo funkcj
zwolnienia pami ci i zako czył program. W Windows niestety
D:\KATALOG\WIN1.EXE okienko nie zamknie si samo w sposób standardowy. W Windows,
jak wiesz, mo emy mie otwarte jednocze nie wiele okien
i "kliknij" myszk na klawiszu [OK] w okienku. programów a aktywne jest (tylko jedno) zawsze to okno, do
którego przeka emy tzw. focus. Okno to mo na rozpozna po
Na ekranie pojawi si okno naszej aplikacji. Okno jest ciemnym pasku tytułowym. Wła nie z przyj cia takiego sposobu
wyposa one w: podziału zasobów Windows pomi dzy aplikacje wynika skutek
praktyczny - okno nie zamknie si automatycznie po zako czeniu
- Pasek z tytułem (Caption) - np.: A:\WIN1.EXE ; programu - lecz wył cznie na wyra ne yczenie u ytkownika. API
- Klawisz zamykania okna i rozwini cia standardowego menu (tzw. Windows zawiera wiele gotowych funkcji (np. CloseWindow() -
menu systemowego Windows) - [-] ; zamknij okno, DestroyWindow() - skasuj okno i in.), z których
- Paski przewijania poziomego i pionowego; mo e skorzysta programista pisz c aplikacj . Nie jeste my wi c
- Klawisze MINIMIZE i MAXIMIZE (zmniejsz do ikonki | powi ksz na całkiem bezradni.
cały ekran) w prawym górnym naro niku okna; Spróbuj skompilowa w opisany wy ej sposób i uruchomi pierwsz
aplikacj w takiej wersji:
Program znajduje si w wersji .EXE na dyskietce doł czonej do
ksi ki. Mo esz uruchomi go z poziomu Mened era Plików (Windows #include <stdio.h>
File Manager), Mened era Programów (Windows Program Manager) lub void main()
{
z DOS-owskiego wiersza rozkazów (DOS Command Line): printf(" Pierwsza Aplikacja \n Dla MS Windows ");
}
C\>WIN A:\WIN1.EXE[Enter]
Jak łatwo si przekona , całkowicie klasyczny, w pełni
Co mo e nasza pierwsza aplikacja? nieobiektowy program WIN1.C b dzie w Windows działa dokładnie
tak samo. Nasze aplikacje nie musz bynajmniej by całkowicie
- Typow dla Windows technik drag and drop - poci gnij i upu obiektowe, chocia zastosowanie obiektowej techniki
mo esz przy pomocy myszki przesuwa okno naszej pierwszej programowania pozwala zmusi nasz komputer do zdecydowanie
aplikacji po ekranie ("ci gn c" okno za pasek tytułowy). wydajniejszego działania.
wewn trz kompilatora DOS'owskiego rozkazem Run | Run. Dla przykładu spróbujmy skompilowa i uruchomi w rodowisku
* Aplikacje skompilowane ( ci lej - skonsolidowane) do wersji Windows jeden z wcze niejszych programów - tabliczk mno enia.
okienkowej mo emy uruchamia wewn trz Windows z poziomu Zwró uwag na doł czony dodatkowy plik WINDOWS.H i nowy typ
Mened era Plików b d Mened era Programów rozkazem Uruchom z wska nika. Zamiast zwykłego
menu Plik.
* Dodatkowe pliki nagłówkowe .H i biblioteki .LIB .DLL znajduj char *p ...
si w katalogach LPSTR p ...
\BORLANDC\INCLUDE
\BORLANDC\OWL\INCLUDE LPSTR - to Long Pointer to STRing - daleki wska nik do ła cucha
\BORLANDC\LIB tekstowego. Jest to jeden z "ulubionych" typów Windows.
\BORLANDC\OWL\LIB
cie ki dost pu do tych katalogów nale y doda do roboczych /* WIN2.CPP: */
katalogów kompilatora w okienku Options | Directories... /* - Tablica dwuwymiarowa
* Aplikacje nie korzystaj ce z funkcji Windows API nie musz - Wskazniki do elementów tablicy */
doł cza okienkowych plików nagłówkowych. Je li jednak
zechcemy zastosowa funkcje i dane (stałe, struktury, #include <windows.h>
obiekty, itp.) wchodz ce w skład: #include <iostream.h>
- Windows API #include <stdio.h>
- Windows Stock Objects - obiekty "ze składu Windows"
- biblioteki klas Object Windows Library int T[10][10], *pT, i, j, k;
nale y doł czy odpowiedni plik nagłówkowy: char spacja = ' ';
#include <windows.h>
#include <windowsx.h> LPSTR p1 = " TABLICZKA MNOZENIA (ineksy)\n";
#include <owl.h> LPSTR p2 = " Inicjujemy i INKREMENTUJEMY wskaznik:\n";
LPSTR p3 = "... nacisnij cokolwiek (koniec)...";
TYPOWE BŁ DY I KŁOPOTLIWE SYTUACJE:
void main()
* Nale y pami ta o ustawieniu wła ciwych katalogów roboczych {
kompilatora Options | Directories... printf(p1);
* Przy bardziej skomplikowanych aplikacjach mo e wyst pi for (i = 0; i < 10; i++)
potrzeba dobrania innego (zwykle wi kszego) modelu pami ci. {
Modelem domy lnym jest model Small. Inne parametry pracy for (j = 0; j < 10; j++)
kompilatora ustawia si podobnie za pomoc menu Options. { T[i][j] = (i + 1)*(j + 1);
if (T[i][j] < 10) cout << T[i][j] << spacja << spacja;
else
cout << T[i][j] << spacja;
LEKCJA 39: KORZYSTAMY ZE STANDARDOWYCH ZASOBÓW }
Windows. cout << '\n';
________________________________________________________________ }
W trakcie tej lekcji dowiesz si , jak korzysta z zasobów printf(p2);
Windows bez potrzeby wnikania w wiele szczególów technicznych pT = &T[0][0];
interfejsu aplikacji - Windows API. for (k = 0; k < 10*10; k++)
________________________________________________________________ {
if (*(pT+k) < 10) cout << *(pT + k) << spacja << spacja;
Poniewa nasze programy mog korzysta ze standardowych zasobów else
Windows, na pocz tku b dziemy posługiwa si okienkami cout << *(pT + k) << spacja;
standardowymi. Pocz wszy od aplikacji WIN3.EXE "rozszerzymy if ((k + 1)%10 == 0) cout << '\n';
ofert " do dwu podstawowych typów: }
printf(p3);
* Standardowe główne okno programu (Default main window). getchar();
To takie wła nie okno, jakie dostały nasze pierwsze aplikacje }
WIN1.EXE.
* Okienkiem dialogowym (Dialog box), Wybrali my dla aplikacji standardowe główne okno (Main Window),
a dokładniej najprostszym rodzajem okienek dialogowych - tzw. poniewa istnieje potrzeba pionowego przewijania okna w celu
okienkami komunikatów - Message Box. przejrzenia pełnego wydruku obu tablic.
Zastosowanie okienka dialogowego pozwoli nam na wprowadzenie do [???] Dlaczego ten tekst jest nierówny???
akcji klawiszy (buttons). ________________________________________________________________
Niestety, znaki w trybie graficznym Windows nie maj stałej
________________________________________________________________ szeroko ci (jak było to w trybie tekstowym DOS). Niektóre
aplikacje przeniesione ze rodowiska DOS b d sprawia kłopoty.
UWAGA: ________________________________________________________________
Niestety nie wszystkie tradycyjne funkcje typu printf(),
scanf(), gets() itp. zostały zaimplementowane dla Windows! APLIKACJE DWUPOZIOMOWE.
Pisz c własne programy mo esz przekona si o tym dzi ki opisowi
Zastosujemy teraz najprostszy typ okienka dialogowego - okienko
funkcji w Help. Funkcj nale y odszuka w Help | Index. Oprócz kamunikatów (Message Box), nasze nast pne aplikacje mog by ju
przykładu zastosowania znajdziesz tam tabelk typu:
nie jedno- a dwupoziomowe. Typowe post powanie okienkowych
DOS Unix Windows ANSI C C++ Only aplikacji bywa takie:
cscanf Yes
fscanf Yes Yes Yes Yes * program wy wietla w głównym oknie to, co ma do powiedzenia;
scanf Yes Yes Yes * aby zadawa pytania stosuje okienka dialogowe, b d okienka
sscanf Yes Yes Yes Yes komunikatów;
* funkcja okienkowa (u nas MessageBox()) zwraca do programu
[Yes] oznacza "zaimplementowana". Dlatego wła nie w dalszych decyzj u ytkownika;
programach przykładowych dla wersji 3.0 nale y np. stosowa np. * program główny analizuje odpowied i podejmuje w głównym oknie
makro getchar() zamiast tradycyjnego getch() zaimplementowane
dla Windows ju w wersji BC++ 3.0. stosowne działania.
116
Prze led my ewolucj powstaj cej w taki sposób aplikacji. - główne okno aplikacji
- dwa okienka komunikatów (Dopisywanie i KONIEC)
STADIUM 1. Tekst w głównym oknie. - jeden klawisz - [OK]
Zaczniemy tworzenie naszej aplikacji tak: Ła cuchy tekstowe przeznaczone do pola tekstowego okienka
pobierane s z tablicy napisy[4][20] (cztery napisy po max. 20
/* WINR1.CPP: */ znaków) przy pomocy wska nika p2. MB_OK to predefiniowana stała
/* Stadium 1: Dwa okienka w jednym programie */ (Message Box OK - key identifier - identyfikator klawisza [OK]
dla okienek komunikatów).
# include <stdio.h>
# include <windows.h> /* WINR3.CPP: */
/* Stadium 3: Dwa okienka steruj p tl */
char *p1 = "Teraz dziala \n funkcja \n MessageBox()";
char *p2 = "START"; # include <windows.h>
int wynik; # include <stdio.h>
HWND hwndParent - identyfikator macie ystego okna (głównego okna W tym stadium stosujemy:
aplikacji). Poniewa nie wiemy póki co pod jakim numerem - główne okno aplikacji
(identyfikatorem) Windows zarejestruj nasz aplikacj - - dwa okienka komunikatów (Dopisywanie i KONIEC)
wpisujemy 0 - dwa klawisze - [OK] i [Anuluj] (OK/Cancel)
LPCSTR lpszText - daleki wska nik do ła cucha tekstowego - jedn ikon [STOP]
wewn trz okienka.
LPCSTR lpszTitle - daleki wska nik do ła cucha tekstowego - Zwró uwag , e tym razem sprawdzamy, który klawisz wybrał
tytułu okienka komunikatu. u ytkownik w okienku. Odbywa si to tak:
UINT Style - UINT = unsigned int; numer okre laj cy zawarto
okienka. if( MessageBox(0, p2, p1, MB_ICONSTOP | MB_OKCANCEL) == IDOK)
int Return Value - identyfikator klawisza, który wybrał
u ytkownik w okienku komunikatu. IDOK jest predefiniowan stał - kodem klawisza [OK] (ang.
OK-key IDentifier - identyfikator klawisza OK). Identyfikatory
[!!!] UWAGA ró nych zasobów Windows s liczbami całkowitymi. Je li jeste
________________________________________________________________ dociekliwy Czytelniku, mo esz sprawdzi - jaki numer ma klawisz
Deklaracje wska ników do tekstów powinny wygl da tak: [OK] rozbudowuj c tekst aplikacji np. tak:
LPCSTR p1 = "Napis1", p2 = "Tekst2";
ale C++ mo e samodzielnie dokona forsowania typów i zamieni int Numer;
typ char* na typ LPCSTR (lub LPSTR). ...
________________________________________________________________ Numer = MessageBox(0, p2, p1, MB_ICONSTOP | MB_OKCANCEL);
printf("\nKlawisz [OK] ma numer: %d", Numer);
/* WINR2.CPP: */ if(Numer == IDOK) ...
/* Stadium 2: Dwa okienka ze zmienn zawaro ci */
Zwró uwag na sposób wykorzystania zasobów w funkcji
# include <windows.h> MessageBox(). Identyfikatory zasobów, które chcemy umie ci w
# include <stdio.h> okienku s wpisywane jako ostatni czwarty argument funkcji i
mog by sumowane przy pomocy znaku | (ang. ORing), np.:
char *p2, *p1 = "Dopisywanie:";
char napisy[4][20] = { "Borland ", "C++ ", "dla ", "Windows" }; MessageBox(0,..,.., MB_ICONSTOP | MB_OKCANCEL);
void main() oznacza umieszczenie ikony STOP i klawiszy [OK] i [Anuluj]. Kod
{ zwracany przez funkcj mo e by wykorzystywany we wszelkich
printf("\n\n\n Hello World dla WINDOWS!"); konstrukcjach warunkowych (switch, case, for, while, if-else,
printf("\n AUTOR: ..................."); itp.).
Warto w tym momencie zwróci uwag na kilka typowych dla Rysunek poni ej przedstawia ró ne stadia działania opisanych
okienkowych aplikacji mechanizmów. powy ej aplikacji.
* Je li naci niemy klawisz na klawiaturze, b d klawisz myszki, Je li postanowisz napisa praktyczn aplikacj dla Windows, jest
obsługa takiego zdarzenia mo e nast powa na dwa sposoby.
Najpierw Windows pobieraj kod klawisza i dokonuj to zwykle program znacznie dłu szy, w którym trzeba przemy le
"kolejkowania" (podobnie jak DOS-owski bufor klawiatury). sposób organizacji p tli, wyra e warunkowych i sposoby
Nast pnie przekazuj kod klawisza aplikacji do obsługi. Je li wykorzystania zasobów.
aplikacja czeka na klawisz i potrafi obsłu y takie zdarzenie
(np. funkcja MessageBox(), b d makro getchar(), czy operator [!!!]UWAGA
cin >> w programie głównym), obsługa zdarzenia zostaje ________________________________________________________________
zako czona. Je li aplikacja nie potrafi obsłu y zdarzenia - Okienka mog by "modalne" i "nie-modlane". Okienko "modalne" to
obsługa przekazywaba jest stadardowym funkcjom obsługi (Event
Handler) Windows. takie okienko, które do momentu jego zamkni cia uniemo liwia
* Kiedy na ekranie pojawia si okienko dialogowe (tu: u ytkownikowi działania w innych oknach (tej samej aplikacji,
komunikatów) zostaje mu przekazany tzw. focus - czyli aktywno . b d innych aplikacji) znajduj cych si na ekranie. W ramach
parametru Styl mo esz stosowa predefiniowane stałe
Naci ni cie [Entera] spowoduje zadziałanie tego klawisza w MB_APPMODAL
okienku, który wła nie ten focus otrzymał (tu zwykle pierwszego MB_TASKMODAL
z lewej). itp.
* je li naci niemy klawisz specjalny, którego obsług w sposób okre laj ce stopie "modalno ci" okienka (na poziomie zadania -
standardowy powinny załatwia Windows - obsługa takiego TASK, aplikacji - APP, itp.).
zdarzenia zostaje przekazana domy lnej funkcji Windows (ang. ________________________________________________________________
Default Event Handler). Tak jest w przypadku klawiszy ze
strzałkami (przewijanie w oknie), [Tab], [Alt]+[F4], itp.
LEKCJA 40: STRUKTURA PROGRAMU PROCEDURALNO -
/* WINR5.CPP: */ ZDARZENIOWEGO
/* Stadium 5: Zmiana wielko ci i nazwy okienka. */ PRZEZNACZONEGO DLA WINDOWS.
________________________________________________________________
# include <windows.h> W trakcie tej lekcji poznasz ogóln budow interfejsu API
# include <iostream.h> Windows i dowiesz si , co z tego wynika dla nas - autorów
# include <string.h> programów przeznaczonych dla Windows.
________________________________________________________________
char tytul[80] = "Dopisywanie: ";
char *p0, *p2; W przeciwie stwie do długich liniowych programów przeznaczonych
char *p1 = "UWAGA: Ponawianie proby \n oznacza: WYDRUKUJE I dla DOS, w naszych programach dla Windows b dziemy pisa co
ZAPYTAM"; na kształt krótkich odcinków programu i przekazywa sterowanie
char *p3 = "I to by bylo na tyle...\n Konczymy ???"; Windows. Jest to bardzo wa na cecha - kod programu jest zwykle
char *p4 = "UWAGA: KONIEC ?"; silnie zwi zany z Windows w taki sposób, e u ytkownik mo e w
char napisy[5][20] = { "Borland ", "C++ ", "dla ", "Microsoft", du ym stopniu decydowa o sposobie (kolejno ci) wykonywania
118
programu. Praktycznie robi to poprzez wybór opcji-klawiszy w w unsigned int (word) słowo
dowolnej kolejno ci. Przy takiej filozofii w dowolnym momencie x,y short x,y coordinate współrz dne x,y (typ: short)
powinni my mie mo liwo przeł czenia si do innego programu ________________________________________________________________
(innego okna) i nasz program powinien (bez zauwa alnej zwłoki)
przekaza sterowanie, nie zagarniaj c i nie marnuj c czasu CPU. O PROGRAMOWANIU PROCEDURALNO - ZDARZENIOWYM DLA
Z tego powodu kod programu powinien by bardzo WINDOWS.
"zmodularyzowany". Ka da sekcja kodu powinna by odseparowana i
ka da, po wykonaniu powinna przekazywa sterowanie do Windows. W proceduralno-sekwencyjnych programach DOS'owskich sterowanie
jest przekazywane mniej lub bardziej kolejno kolejnym
NOTACJA W GIERSKA I NOWE TYPY DANYCH. instrukcjom w taki sposób, jak yczył sobie tego programista. W
Windows program-aplikacja prezentuje u ytkownikowi wszystkie
Tworzenie zdarzeniowych programów dla Windows wymaga kilku dost pne opcje w formie widocznych na ekranie obiektów (visual
wst pnych uwag na temat nowych typów danych. Okienkowe typy s objects) do wyboru przez u ytkownika. Program funkcjonuje zatem
definiowane w plikach nagłówkowych (WINDOWS.H, WINDOWSX.H, według zupełnie innej koncepcji nazywanej "programowaniem
OWL.H zdarzeniowym" (ang. event-driven programming). Mo na powiedzie ,
itp) i maj posta najcz ciej struktury, b d klasy. Typowe e za przebieg wykonania programu nie jest odpowiedzialny tylko
sposoby deklaracji w programach okienkowych s nast puj ce: programista lecz cz tej odpowiedzialno ci przejmuje
u ytkownik i to on decyduje w jaki sposób przebiega wykonanie
HWND hWnd - WiNDow Handle - identyfikator okna programu. U ytkownik mo e wybra w dowolnym momencie dowoln
HWND hWnd - typ (predefiniowany), hWnd - zmienna spo ród wszystkich oferowanych mu opcji a program powinien
HINSTANCE hInstance - Instance Handle - identyfikator danego zawsze zareagowa poprawnie i równie szybko. Jest oczywiste, e
wyst pienia (uruchomienia) programu pisz c program nie mo emy przewidzie w jakiej kolejno ci
PAINTSTRUCT - struktura graficzna typu PAINTSTRUCT u ytkownik b dzie wybierał opcje/rozkazy z menu. Przeciwnie
ps - nasza robocza struktura (zmienna) powini my napisa program w taki sposób by dla ka dego rozkazu
WNDCLASS - struktura (a nie klasa wbrew myl cej nazwie) istniał oddzielny kod. Jest to ogólna koncepcja, na której
POINT - struktura (współrz dne punktu - piksela na ekranie) opiera si programowanie zdarzeniowe.
RECT - struktura (współrz dne prostok ta)
BOOL - typ signed int wykorzystywany jako flaga (TRUE/FALSE) W przeciwie stwie do programów proceduralno - sekwencyjnych,
WORD - unsigned int które nale y czyta od pocz tku do ko ca, programy dla Windows
DWORD - unsigned long int musz zosta poci te na na mniejsze fragmenty - sekcje - na
LONG - long int zasadzie jedna sekcja - obsługa jednego zdarzenia. Je li
HANDLE, HWND, HINSTANCE - unsigned int (jako nr - identyfikator) zechcesz wy wietli napis "Hello, World", sekcja zdarzeniowego
programu obsługuj ca takie zdarzenie mo e wygl da np. tak:
UINT - j. w. - unsigned int.
Funkcja_Obsługi_Komunikatów_o_Zdarzeniach(komunikat)
W programach okienkowych stosuje si wiele predefiniowanych {
stałych, których znaczenie sugeruje przedrostek i nazwa, np: switch (komunikat_od_Windows)
{
WM_CREATE - Windows Message: Create! - Komunikat Windows: case WM_CREATE:
Utworzy ! (np. okno) ...
WS_VISIBLE - Window Style: Visible - Styl Okna: Widoczne TextOut(0, 0, "Napis: np. Hello world.", dlugosc_tekstu);
ID_... - IDentifier - IDentyfikator break;
MB_... - Message Box - elementy okienka komunikatów
...
W rodowisku Windows stosuje si specjaln notacj nazwan od case WM_CLOSE: // CLOSE - zamkn okno
narodowo ci swojego wynalazcy Karoja Szimoni - notacj .... break;
w giersk . Sens notacji w gierskiej polega na dodaniu do nazwy ..................... itd.
zmiennej okre lonych liter jako przedrostka (prefix). }
Litery-przedrostki stosowane w notacji w gierskiej zebrano w
Tabeli poni ej. Pomi dzy nazewnictwem Microsofta a Borlanda a w przypadku obiektowego stylu programowania - metoda
istniej wprawdzie drobne rozbie no ci, ale ogólne zasady mo na obsługuj ca to zdarzenie (nale ca np. do obiektu
odnie zarówno do BORLAND C++ 3+...4+, jak i Microsoft C++ Obiekt_Główne_Okno - TMainWindow) mo e wygl da np. tak:
6...7, czy Visual C++.
void TMainWindow::RysujOkno()
Notacja w gierska {
________________________________________________________________ TString Obiekt_napis = "Hello, World";
Prefix Skrót ang. Znaczenie int dlugosc_tekstu = sizeof(Obiekt_napis);
________________________________________________________________ TextOut(DC, 10, 10, Obiekt-napis, dlugosc_tekstu);
}
a array tablica
b bool zmienna logiczna (0 lub 1) Taki fragment kodu programu jest specjalnie przeznaczony do
by unsigned char znak (bajt) obsługi jednego zdarzenia (ewent-ualno ci). W okienku wykonuje
c char znak si operacja PAINT (maluj). "Malowanie" okna mo e si odbywa
cb count of bytes liczba bajtów albo po raz pierwszy, albo na skutek przesuni cia. Programy
cr color reference value okre lenie koloru zdarzeniowe tworzone w C++ dla Windows b d zbiorem podobnych
cx, cy short (count x, y len.) x-ilo , y-długo (short) "kawałków" nast puj cych w tek cie programu sekcja za sekcj .
dw unsigned long liczba długa bez znaku Oto jak działa program zdarzeniowy: kod programu, podzielony na
double word podwójne słowo sekcje obsługuj ce poszczególne zdarzenia koncentruje si wokół
fn function funkcja interfejsu.
pfn pointer to function wsk. do funkcji
h handle "uchwyt" - identyfikator FUNKCJE WinMain() i WindowProc().
i integer całkowity
id identifier identyfikator W programach pisanych w standardowym C dla Windows u ywane s
n short or int krótki lub całkowity dwie najwa niejsze funkcje: WinMain() i WindowProc().
np near pointer wska nik bliski
p pointer wska nik ________________________________________________________________
l long długi
lp long pointer wska nik typu long int UWAGA:
lpfn l. p. to function daleki wska n. do funkcji Funkcji WindowProc() mo na nada dowoln nazw , ale WinMain()
s string ła cuch znaków musi si zawsze nazywa WinMain(). Jest to nazwa zastrze ona
sz string terminated '\0' ła cuch ASCIIZ podobnie jak main() dla aplikacji DOSowskich.
tm text metric miara tekstowa ________________________________________________________________
119
Komunikaty Windows mo na tak e podzieli umownie na nast puj ce
kategorie:
Funkcja WinMain() powoduje utworzenie okna programu umo liwiaj c
1. Komunikaty dotycz ce zarz dzania oknami (Windows Managenent
zdefiniowanie i zarejestrowanie struktury "okno" (struct Msg.):
WNDCLASS) a nast pnie powoduje wy wietlenie okna na ekranie. Od WM_ACTIVATE (zaktywizuj lub zdezaktywizuj okno), WM_PAINT,
tego momentu zarz dzanie przejmuje funkcja WindowProc(). W WM_MOVE, WM_SIZE, WM_CLOSE, WM_QUIT.
typowej proceduralno - zdarzeniowej aplikacji dla Windows to
wła nie funkcja WindowProc() obsługuje pobieranie informacji od Bardzo istotnym szczegółem technicznym jest problem
u ytkownika (np. naci ni cie klawisza lub wybór z menu). Funkcja przekazywania aktywno ci pomi dzy oknami. Szczególnie cz sto
wyst puje potrzeba przekazania aktywno ci do elementu
WindowProc() robi to dzi ki otrzymywaniu tzw. komunikatów (ang. steruj cego. Je li hEditWnd b dzie identyfikatorem (window
Windows message). handle) okienka edycyjnego:
Przedrostek WM_ to skrót od Windows Message - komunikat Windows. case WM_CLOSE: /* Zamkni cie okna */
....
Wymiana komunikatów w rodowisku Windows mo e przebiega w ró ny break;
default: /* wariant domy lny: standardowa obsługa
sposób - zale nie od ródła wywołuj cego generacj komunikatu i .... przez standardow funkcj Windows */
od charakteru zdarzenia. Ze wzgl du na ródło mo na komuniakty }
umownie podzieli na nast puj ce grupy: }
________________________________________________________________
1. Działanie u ytkownika (np. naci ni cie klawisza) powoduje UWAGA:
wygenerowanie komunikatu. Poniewa komunikatów "interesuj cych" dan aplikacj mo e by
2. Program - aplikacja wywołuje funkcj Windows i powoduje ponad 100 a sposobów reakcji u ytkownika jeszcze wi cej, w
przesłanie komunikatu do aplikacji. "powa nych" aplikacjach tworzone s cz sto struktury decyzyjne o
3. rodowisko Windows przesyła komunikat do programu.
4. Dwie aplikacje zwi zane mechanizmem dynamicznej wymiany wi kszym stopniu zło ono ci. Je li istnieje potrzeba
danych (Dinamic Data Exchange - DDE) wymieniaj komunikaty. optymalizacji działania programów stosuje si struktury dwu
typów:
120
* hierarchia warto ci (Value Tree) i nale c do Windows API) funkcja GetMessage(). Ta funkcja
* drzewo analizy zdarze (Event Tree). wypełnia struktur komunikatów i zwraca warto . Zwracana przez
Utworzone w taki sposób tzw. "Drzewo decyzyjne" nazywane tak e funkcj warto jest ró na od zera, je eli otrzymany wła nie
"Drzewem analizy zdarze " mo e by wielopoziomowe. Widoczny komunikat był czymkolwiek za wyj tkiem WM_QUIT. Komunikat
powy ej pierwszy poziom drzewa (pierwszy przesiew) realizowany WM_QUIT jest komunikatem ko cz cym prac ka dej aplikacji dla
jest zwykle przy pomocy instrukcji switch a nast pne przy pomocy Windows. Je li otrzymamy komunikat WM_QUIT powinni my przerwa
p tl pobierania komunikatów i zako czy prac funkcji
drabinek typu if-else-if-break. Schemat if-else-if-break cz sto WinMain(). Taka sytuacja oznacza, e wi cej komunikatów nie
bywa zast powany okienkami dialogowymi. b dzie. Po uwzgl dnieniu tych warunków p tla mo e wygl da tak:
________________________________________________________________
int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance, \
LPSTR lpszCmdLine, int nCmdShow)
Parametry wParam i lParam przechowuj parametry istotne dla ....
danego komunikatu. wParam ma długo pojedynczego słowa (word) a while(GetMessage(&msg,NULL,0,0)) //Poki nie otrzymamy WM_QUIT
{
lParam ma długo podwójnego słowa (long). Je li, dla przykładu, ....
}
okno zostało przesuni te, te parametry zawieraj nowe
współrz dne okna. Po naci ni ciu przez u ytkownika klawisza generowany jest
komunikat WM_KEYDOWN. Jednak e z faktu otrzymania komunikatu
Je eli program ma by programem zdarzeniowym, powinni my przed WM_KEYDOWN nie wynika, który klawisz został przyci ni ty, czy
podj ciem jakiejkolwiek akcji zaczeka a Windows przy l nam była to du a, czy mała litera. Funkcj TranslateMessage()
komunikat o tym, jakie zdarzenie nast piło. Wewn trz Windows (PrzetłumaczKomunikat) stosuje si do przetłumaczenia komunikatu
tworzona jest dla komunikatów kolejka (ang message queue).
Dzi ki istnieniu kolejkowania otrzymujemy komunikaty pobierane z WM_KEYDOWN na komunikat WM_CHAR. Komunikat WM_CHAR
przekazuje
kolejki pojedynczo. Je li u ytkownik przesunie okno a nast pnie przy pomocy parametru wParam kod ASCII naci ni tego klawisza.
przyci nie klawisz, to Windows wywołaj funkcj WindowProc() Funkcj TranslateMessage() stosujemy w p tli pobierania
najpierw z parametrem WM_MOVE a nast pnie z parametrem komunikatów tak:
WM_KEYDOWN.
int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance, \
Jednym z najwa niejszych zada funkcji WinMain() jest utworzenie LPSTR lpszCmdLine, int nCmdShow)
....
kolejki dla komunikatów i poinformowanie Windows, e komunikaty while(GetMessage(&msg, 0, 0, 0))
do naszego programu nale y kierowa pod adresem funkcji {
WindowProc(). W tym celu stosuje si daleki wska nik do TranslateMessage(&msg);
procedury okienkowej lpfn (Long Pointer to Function). Poza tym ....
funkcja WinMain() tworzy okno (okna) i wy wietla je na ekranie w }
pozycji pocz tkowej. Kiedy program zostaje po raz pierwszy W tym stadium program jest gotów do przesłania komunikatu do
załadowany i uruchomiony - Windows najpierw wywołuj funkcj funkcji - procedury okienkowej WindowProc(). Posłu ymy si w tym
WinMain().
celu funkcj DispatchMessage() (ang. dispatch - odpraw, przeka ,
Windows manipuluj komunikatami posługuj c si struktur MSG (od
DispatchMessage = OtprawKomunikat). Funkcja WinMain()
messages - komunikaty). Struktura MSG jest zdefiniowana w pliku poinformowała wcze niej Windows, e odprawiane komunikaty
WINDOWS.H w nast puj cy sposób: powinny trafi wła nie do WindowProc().
122
p tl pobierania komunikatów. Ka dy komunikat przeznaczony dla identyfikator kombinacji klawiszy - "accelerator ID". Procedura
głównego okna (lub ewentualnych nastepnych okien potomnych) jest obsługi komunikatów powinna zawiera
hWndMain = CreateWindow(....);
if(hWndMain == NULL) Kod obsługi powiekszania/zmniejszania case WM_SIZE.
{
MessageBox(0, "Klops", "Koniec", MB_OK); wParam zawiera kod operacji - zmniejsz/powi ksz
return (FALSE); lParam zawiera now wysoko i szeroko okna
}
case WM_PAINT:
Wy wietlenie głównego okna na ekranie:
Pobranie kontekstowego identyfikatora urz dzenia. Funkcja
ShowWindow(hWndMain, nCmdShow); BeginPaint() spowoduje w razie potrzeby wysłanie komunikatu
WM_ERASEBKGND (Erase Background - skasuj tło).
P tla komunikatów wykrywaj ca komunikat WM_QUIT:
memset(&ps, 0x00, sizeof(PAINTSTRUCT));
while(GetMessage(&msg, 0, 0, 0)) hDC = BeginPaint(hWnd, &ps);
{
TranslateMessage(&msg); Set Background Mode - ustaw rodzaj tła (tu: przezroczyste):
DispatchMessage(&msg);
} SetBkMode(hDC, TRANSPARENT);
Główna procedura obsługi okna WindowProc(). Aplikacja powinna wykre li obszar roboczy okna posługuj c sie
grafik GDI i (Graficzny Interfejs Urz dzenia - analogia do
Instrukcja switch przeł cza do odpowiedniego wariantu działania graficznego standardu BGI w rodowisku DOS). Struktura ps typu
- obsługi odpowiedniego komunikatu. Musz tu znajdowa sie PAINSTRUCT zwrócona przez BeginPaint() wskazuje prostok t do
procedury obsługi wszystkich interesujacych nas działa zamalowania.
uzytkownika i ogólnych komunikatow Windows (np. WM_CLOSE). Je li
Wypisanie tekstu w głównym oknie aplikacji:
wyst pi taki komunikat, którego obsługa nie została
przewidziana, obsługa jest przekazywana, do funkcji okienkowej TextOut(hDC, 0, 0, (LPSTR) "Hello, world.", strlen("Hello,
DefWindowProc() - obsług przejmuj Windows. world."));
Komunikaty inicjowane przez u ytkownika s rozpatrywane
zasadniczo jako WM_COMMAND. Rozkaz wybrany z menu lub Funkcja TextOut() pracuje w trybie graficznym, wi c (podobnie
odpowiadaj ca mu kombinacja klawiszy jest przekazywana przy jak inne funkcje graficzne Windows API) otrzymuje jako argument
pomocy pierwszego parametru komunikatu - wParam. Kod tzw. "kontekst urz dzenia" - hDC.
odpowiadaj cy rozkazowi z menu nazywa sie "control menu ID", a
123
Zamykanie okna: korzysta z Debuggera), pojawiło si natomiast nowe menu Browse
(przegl danie). Rozkazy, których tradycyjnie szukali my w menu
case WM_CLOSE: Debug zostały rozrzucone do innych menu. I tak:
DestroyWindow(hWnd);
if (hWnd == hWndMain) Menu Compile zawiera:
PostQuitMessage(0);
Compile (kompilacja do *.OBJ),
Je li zamkni te zostało główne okno aplikacji, funkcja Make (kompilacja i konsolidacja do *.EXE),
PostQuitMessage() wysyła do Windows komunikat, e aplikacja Link (konsolidacja bez powtórnej kompilacji),
zako czyła działanie i okno aplikacji zostało usuni te. W tym Build all (konsolidacja wszystkich modułów),
stadium stosuje si funkcje PostQuitMessage() i Information... (informacja o przebiegu kompilacji),
PostAppMessage(). Pozostale przypadki s obsługiwane przez Remove messages (usuwanie komunikatów z pliku wynikowego)
wariant domy lny - default. Przekazanie komunikatu do obsługi
przez Windows. Menu Run zawiera:
if (!RegisterClass(&wndclass)) return -1; modułu *.CPP) i do poprawnego działania wymaga kilkadziesi t lub
}
nawet kilkaset kilobajtów dodatkowej przestrzeni na dysku.
Typowe obiekty ze składu Windows to
[!!!]UWAGA
HBRUSH P dzel; i ________________________________________________________________
HPEN Ołówek;
Je li przenosisz projekt na dyskietk i tam kontynuujesz prac
Nale y tu zwróci uwag jeszcze na dwa szczegóły techniczne. DC nad projektem, pami taj, e mo e zabrakn miejsca na
i GDI - Device Context, Graphics Device Interface - to tzw. prekompilowany plik .SYM.
kontekst urz dzenia i graficzny interfejs urz dzenia. Pozwala to ________________________________________________________________
Windows działa skutecznie w trybie "Device Independent"
(niezale nym od sprz tu).
Czytelnik zechce sam sprawdzi w jakim stopniu przyspieszy to
kompilacj naszego własnego programu proceduralno -
LEKCJA 42: KOMPILATORY "SPECJALNIE DLA Windows". zdarzeniowego WINPZ1.CPP:
________________________________________________________________
Z tej lekcji dowiesz si , czym ró ni si kompilatory WINZ1.CPP. Jednomodułowa aplikacja proceduralno - zdarzeniowa
przeznaczone dla pracy w rodowisku Windows. dla Windows.
________________________________________________________________ ________________________________________________________________
#include <windows.h>
W IDE i w sposobie zachowania zaszły istotne zmiany. Posługuj c #pragma argused
si Turbo C++ z pakietu BORLAND C++ 3.0 lub BCW z pakietu 3.1
mo emy korzysta z uroków i usług Windows szerzej ni do tej long FAR PASCAL WndProc (HWND, unsigned, WORD, LONG) ;
pory. Mo emy otwiera wiele okien i uruchamia bezpo rednio z
poziomu IDE okienkowe aplikacje. W głównym menu kompilatora int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance,
zaszły pewne zmiany (sygnalizuj ce obiektowo- i okienkowo - LPSTR lpszCmdLine, int nCmdShow )
zorientowan ewolucj pakietów Borlanda), na które warto zwróci {
uwag . WNDCLASS Okno1;
MSG komunikaty;
Znikn ło menu Debug (co wcale nie oznacza, e nie mo emy HWND NrOkna;
124
LPSTR LongPtr1 = "Okno 1";
LPSTR lp2 = "AM: BC++ 3..4/Reczne sterowanie (1)"; Program demonstruje opisane wy ej mechanizmy, mo e by
uruchamiany wielokrotnie i sprowadzony do ikony. Z uwagi na brak
if (hPrevInstance == 0)
{ zdefiniowanych dodatkowych zasobów (brak w projekcie plików:
Okno1.style= CS_HREDRAW | CS_VREDRAW ; .RC - resources - zasoby
Okno1.lpfnWndProc= WndProc; .ICO - ikona
Okno1.cbClsExtra = 0; .DEF - definicji
Okno1.cbWndExtra= 0; .PRJ lub .IDE - projektu
Okno1.hInstance = hInstance; .DSK - konfiguracyjnego
Okno1.hCursor = LoadCursor(0, IDC_CROSS ); itp.)
Okno1.hbrBackground= GetStockObject(WHITE_BRUSH );
Okno1.lpszMenuName= 0; podczas kompilacji programu wyst pi dwa komunikaty
Okno1.lpszClassName= LongPtr1; ostrzegawcze. Komunikaty te mo na zignorowa .
if (!RegisterClass(&Okno1)) A oto druga przykładowa aplikacja w tym samym stylu. Tym razem
return 0; funkcja okienkowa reaguje na naci ni cie lewego klawisza myszki,
}
co powoduje wygenerowanie komunikatu WM_LEFTBUTTONDOWN.
NrOkna = CreateWindow(LongPtr1, lp2, WS_VISIBLE |
WS_SYSMENU | Program WINZ-2.CPP
WS_MINIMIZEBOX | WS_VSCROLL | WS_MAXIMIZEBOX, ________________________________________________________________
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, #include <windows.h>
0, 0, hInstance, 0); #include <string.h>
#pragma argused
ShowWindow(NrOkna, nCmdShow);
UpdateWindow(NrOkna); char napis[10];
int X, Y;
while (GetMessage(&komunikaty, 0, 0, 0))
{ LONG FAR PASCAL WndProc (HWND, WORD, WORD, LONG);
TranslateMessage(&komunikaty );
DispatchMessage(&komunikaty ); int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance,
} LPSTR lpszCmdLine, int nCmdShow )
return 0; {
} WNDCLASSwndClass;
MSGmsg;
long FAR PASCAL WndProc (HWND NrOkna, unsigned HWNDhWnd;
KomunikatWindows, LPSTR Lp1 = "Mysza1";
LPSTR lp2 = "WINPZ2: Wykrywanie Lewego Klawisza
WORD wParam, LONG lParam) Myszki";
{
HDC NrKontekstu; if (!hPrevInstance)
PAINTSTRUCT struktura_graficzna; {
RECT prostokat; wndClass.style= CS_HREDRAW | CS_VREDRAW ;
wndClass.lpfnWndProc= WndProc;
switch(KomunikatWindows) wndClass.cbClsExtra = 0;
{ wndClass.cbWndExtra= 0;
case WM_PAINT: wndClass.hInstance = hInstance;
{ wndClass.hIcon = 0;
NrKontekstu = BeginPaint(NrOkna, &struktura_graficzna); wndClass.hCursor= LoadCursor(0, IDC_ARROW );
GetClientRect(NrOkna, &prostokat); wndClass.hbrBackground= GetStockObject(WHITE_BRUSH );
TextOut(NrKontekstu,80,50, ": Reczne sterowanie:", 20 ); wndClass.lpszMenuName= 0;
TextOut(NrKontekstu, 5,70, "Tu -->", 6); wndClass.lpszClassName= Lp1;
TextOut(NrKontekstu, 5, 85, "Blad:", 5);
TextOut(NrKontekstu,75,70, "-----------------------------", if (!RegisterClass(&wndClass))
exit(1);
40); }
TextOut(NrKontekstu,30,110, "Programowanie proceduralno -
zdarzeniowe.", 41 ); hWnd = CreateWindow(Lp1, lp2, WS_OVERLAPPEDWINDOW,
TextOut(NrKontekstu,30,135, "Szablon moze zostac rozbudowany CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
0, 0, hInstance, 0);
o inne funkcje.", 47 );
TextOut(NrKontekstu,30,180, "RECZNIE panujemy np. nad:", 25 ShowWindow(hWnd, nCmdShow);
); UpdateWindow(hWnd);
TextOut(NrKontekstu,20,220, "paskiem tytulowym okna, tytulem
while (GetMessage(&msg, 0, 0, 0))
ikonki...", 41); {
TextOut(NrKontekstu, 100, 250, "!KONIEC - [Alt]+[F4]", 20); TranslateMessage(&msg );
DispatchMessage(&msg );
EndPaint(NrOkna,&struktura_graficzna); }
break; return 0;
} }
case WM_DESTROY:
{ LONG FAR PASCAL WndProc (HWND hWnd, WORD Message,
PostQuitMessage(0); WORD wParam, LONG lParam)
break; {
} HDC hDC;
default: PAINTSTRUCT ps;
return DefWindowProc(NrOkna,KomunikatWindows,wParam,lParam); RECT rect;
switch(Message)
} {
return 0; case WM_SIZE:
} hDC = GetDC( hWnd );
125
TextOut(hDC, 50, 100, "Wykrywanie nacisniecia", 22); Wska nik do parametrów uruchomieniowych programu (Arguments)
TextOut(hDC, 50, 120, "lewego klawisza myszki.", 23); pobieranych z wiersza rozkazu nie został ani raz u yty w
TextOut(hDC, 20, 140, "Komunikat o zdarzeniu: ", 22); programie. Na to nic nie mo emy poradzi . Po prostu argumenty
TextOut(hDC, 20, 156, "Left Button Down - LBUTTONDOWN", 31); uruchomieniowe nie s nam potrzebne. Wykonujemy wi c "klik"
(przekazanie "focusa") w okienku edycyjnym i mo emy przej do
TextOut(hDC, 50, 170, "Po wcisnieciu klawisza,", 23); nast pnej czynno ci:
TextOut(hDC, 50, 190,"w biezacej pozycji kursora, pojawi sie
4. Konsolidacja: Compile | Link.
napis <-- Tu!.", 52);
ReleaseDC(hWnd, hDC); W okienku "Message" znów pojawi si ostrze enie:
break;
Linker Warning: No module definition file specified:
case WM_PAINT: using defaults.
hDC = BeginPaint(hWnd, &ps); (brak wyspecyfikowanego pliku definicji .DEF; stosuj warto ci
TextOut(hDC, X,Y, napis, strlen(napis)); domy lne)
EndPaint(hWnd, &ps);
break; I tu ju mo emy co zaradzi . Mo emy zatem pokusi si o
stworzenie naszego pierwszego pliku definicji (nazwa jest troch
case WM_LBUTTONDOWN:
strcpy(napis,"<-- Tu !"); myl ca - chodzi o zdefiniowanie sposobu wykorzystania zasobów
X = LOWORD(lParam); rodowiska Windows).
Y = HIWORD(lParam);
InvalidateRect(hWnd, 0, TRUE); Aby utworzy plik .DEF (jest to plik ASCII) nale y:
UpdateWindow(hWnd);
break; 1. Otworzy nowe okienko edycyjne (nie wychodz c z IDE):
File | New
case WM_DESTROY: Otworzy si okienko NONAMExx.CPP. Ta nazwa nie jest oczywi cie
PostQuitMessage(0); break; najodpowiedniejsza, wi c umieszczamy plik we wła ciwym katalogu
(tym samym, co główny program *.CPP) przy pomocy rozkazu File |
default: Save as...
return DefWindowProc(hWnd, Message, wParam, lParam); i nadajemy plikowi stosown nazw i rozszerzenie *.DEF. Okieno
} pozostaje puste, ma jednak "focus" i now nazw , np.
return 0; C:\..\PR.DEF.
}
3. Redagujemy nasz pierwszy plik definicji, np. tak:
Plik nagłówkowy STRING.H pojawia si ze wzgl du na obecno
funkcji strlen() wyznaczaj cej długo napisu. Zmienne X i Y to NAME JAKAKOLWIEK // <-- nazwa aplikacji
bie ce (wzgl dne) współrz dne kursora myszki w momencie DESCRIPTION 'Opis: A. MAJCZAK, BC C++ 3...4'
naci ni cia klawisza. Program demonstruje nast puj ce efekty: EXETYPE WINDOWS // <-- EXE dla Windows
CODE PRELOAD MOVEABLE DISCARDABLE
X = LOWORD(lParam); DATA PRELOAD MOVEABLE MULTIPLE
HEAPSIZE 4096 // <-- sterta 4 KB
- przekazanie współrz dnej X przy pomocy parametru lParam STACKSIZE 5120 // <-- stos 5 KB
(LOWORD to LOw WORD of the double word - młodsze słowo podójnego
_______________________________________________________________
słowa). UWAGA:
W przypadku tworzenia bibliotek .DLL dane musz mie status
Y = HIWORD(lParam); SINGLE (pojedyncze) zamiast MULTIPLE (wielokrotne). U ycie tu
słowa MULTIPLE pozwoli nam na wielokrotne uruchamianie
Analogicznie - przekazanie współrz dnej Y (HIgh WORD of the aplikacji.
double word). Funkcja InvalidateRect() powoduje uznanie ________________________________________________________________
prostok nego pola za nieaktualne. Funkcja UpdateWindow()
"od wie a" okno. Dzi ki temu tandemowi napis znika i pojawia si Mo naby tu zapyta - po co to robi , skoro u ywamy standardowych
warto ci i obecno tego pliku nie wnosi nic nowego do sposobu
w nowym miejscu. działania naszego programu?
Odpowied jest prosta. Maj c taki plik b dziemy mogli
PROJEKT. prze ledzi stadia tworzenia tzw. projektu (w BC++ 4 bez tego
ani rusz). Zapisujemy zatem plik na dysk:
Aby skompilowa powy sze programy przykładowe nale y:
4. File | Save. (plik .DEF zostaje zapisany na dysku).
1. Uruchomi kompilator C++. Poniewa pracujemy w rodowisku Windows, okno edycji pliku *.DEF
2. Załadowa do okienka edycyjnego (File | Open) plik z tekstem
ródłowym programu. mo emy traktowa podobnie jak ka de inne okno. Najwygodniej
3. Wybra rozkaz Compile z menu Compile. zatem przej do okna edycji głównego pliku ródłowego *.CPP
Przed kompilacj i konsolidacj (je li był inny) ustawi sposób przy pomocy własnego menu systemowego tego okna.
tworzenia kodu wynikowego [Windows EXE].
5. Menu Systemowe [-] | Zamknij.
Kompilacja przebiegnie poprawnie (pami taj o Opcjach i
Katalogach), mimo to pojawi si jednak dwa komunikaty I mo emy przyst pi do tworzenia projektu składaj cego si z dwu
ostrzegawcze. W okienku "Compile Status" (stan/przebieg
kompilacji) pojawi si zawarto : plików: *.CPP i *.DEF. Je li, dla przykładu, przyjmiemy w tym
miejscu, e nasze dwa moduły nazywaj si : WINZ2.CPP i WINZ2.DEF
Lines 3832 (znakomita wi kszo to WINDOWS.H,
prekompilacja byłaby celowa) i s przechowywane w katalogu głównym dysku C:\ , kolejno
Warnings: 1 czynno ci powinna by nast puj ca:
Errors: 0
1. Rozwijamy menu Project ([Alt]+[P] lub myszk ).
Je li wybierzesz klawisz [OK] w okienku "focus" (aktywno ) 2. Wybieramy z menu rozkaz Open Project... (Utwórz projekt).
zostanie przekazana do okienka komunikatów "Message" a tam Pojawia si okienko dialogowe Open Project File z domy lnym
pojawi si napis: rozszerzeniem *.PRJ (w BC 4+ - *.IDE).
3. Do okienka File Name:
Warning: Parameter 'lspzCmdLine' is never used. wpisujemy nazw pliku z opisem projektu: np. WINZ2.PRJ.
W dolnej cz ci ekranu otwiera si okienko
126
Project: WINZ2
4. Wybieramy z menu Project rozkaz Add item... (dodaj element do COMBOBOX - okienko dialogowe kombinowane. Jest
zło eniem klasy EDIT i LISTBOX;
projektu). Pojawia si okienko dialogowe "Add to Project List"
(dodawanie do listy elementów projektu). LISTBOX - oknienko z list (zwykle element
5. Do okienka File Name: wpisujemy nazw głównego pliku składowy okienka dialogowego typu
projektu: WINZ2.CPP (*.cpp jest domy lnym rozszerzeniem). Combo Box.
Plik mo emy wybra tak e z listy w okienku Files: .
6. Wybieramy w okienku dialogowym klawisz [+Add] (dodaj do STATIC - pole statyczne (bez prawa edycji).
projektu). Niewielkie okno zawieraj ce tekst lub
7. Wpisujemy nazw kolejnego pliku wchodz cego w skład projektu
(w tym przypadku WINZ2.DEF). grafik ; słu y z reguły do oznaczania
8. Wybieramy klawisz [+Add] w okienku.
UWAGA: Czynno ci 7) i 8) w przypadku bardziej zło onych innych okien steruj cych.
projektów b d powtarzane wielokrotnie.
9. Wybieramy klawisz [Done] w okienku (zrobione/gotowe). SCROLLBAR - pasek przewijania (pionowy - Vertical
Konfigurowanie projektu zostało zako czone.
10. Przy pomocy rozkazów Compile, Link, Make, Build all, Run Scroll Bar; poziomy - Horizontal
mo emy teraz skompilowa , skonsolidowa i uruchomi nasz program Scroll Bar).
w postaci projektu. Ostrze enie Linkera zniknie. Style klawiszy steruj cych (Button Styles):
po załadowaniu pliku projektu [Open Project] pojawi si lista BS_RADIOBUTTON - Okr gły przeł cznik działaj cy
plików. Do trybu edycji pliku mo esz przj poprzez dwukrotne zwykle na zasadzie @tylko jeden
klini cie pliku na tej li cie. z grupy".
Zwró uwag , e pliki projektów .PRJ ( w Borland 4+ .IDE)
przechowuj równie informacje o konfiguracji. Najwa niejsza z BS_CHECKBOX - - prostok tny przeł cznik [X]
nich to informacja o katalogach, z których korzysta kompilator: wł czaj cy (aktywna) lub
wył czaj cy (nieaktywna)
Options | Directories... | Include opcj . Działa niezale nie od
Options | Directories... | Library pozostałych.
Options | Directories... | Output
________________________________________________________________ Inne style okre laj np. sposób edycji tekstu (ES_LEFT,
ES_MULTILINE, itp.) Szczegóły - patrz system Help - Windows API.
Najwygodniej przechowywa wszystkie pliki wchodz ce w skład Oto przykład utworzenia okna elementu steruj cego typu "Klawisz"
jednego projektu w odr bnym katalogu dyskowym. Dla wprawy załó
odr bny katalog i zapisz tam pliki: (BUTTON to nazwa typu):
LISTBOX - oknienko z list (zwykle element - powoduje wygenerowanie komunikatu WM_COMMAND. Towarzysz ce
składowy okienka dialogowego typu komunikatowi parametry przenosz istotne informacje:
Combo Box.
wParam - identyfikator elementu steruj cego,
STATIC - pole statyczne (bez prawa edycji). lParam - dla wci ni tego klawisza b dzie to BN_CLICKED.
Niewielkie okno zawieraj ce tekst lub
Niektóre komunikaty Windows mog by kierowane do okna elementu
grafik ; słu y z reguły do oznaczania steruj cego i wymusza pewne operacje. Dla przykładu komunikat
WM_GETTEXTLENGTH przesłany do okienka edycyjnego typu Text Edit
innych okien steruj cych. Box (element steruj cy klasy EDIT) jest daniem podania
długo ci tekstu wpisanego wła nie do okienka. Aby Windows
SCROLLBAR - pasek przewijania (pionowy - Vertical wygenerowały komunikat i przesłały go do naszego elementu
steruj cego - musimy "poprosi " przy pomocy funkcji
Scroll Bar; poziomy - Horizontal SendMessage() (Wy lijKomunikat):
Scroll Bar).
DlugTekstu = SendMessage(hEditWnd, WM_GETTEXTLENGHT, 0, 0);
Style klawiszy steruj cych (Button Styles): gdzie:
hEditWnd jest identyfikatorem elementu - okienka edycyjnego
BS_PUSHBUTTON - Klawisz. Okno steruj ce wysyła, po
ka dym wyborze klawisza [???]Robi na "szaro'?
(klikni cie), wiadomo do okna ________________________________________________________________
macie ystego (Parent Window). Podobnie jak opcje w menu - klawisze tak e mog zosta
udost pnione (ang. enable), b d zablokowane (ang. disable).
BS_RADIOBUTTON - Okr gły przeł cznik działaj cy Je li hKlawisz b dzie identyfikatorem elementu steruj cego,
zwykle na zasadzie @tylko jeden mo na go udost pni (1), b d zablokowa (0) przy pomocy
z grupy". funkcji:
Inne style okre laj np. sposób edycji tekstu (ES_LEFT, kilkunastu) plików: .H, .MNU, .DLG, .RC, .DEF, .PRJ, .ICO, .BMP,
ES_MULTILINE, itp.) Szczegóły - patrz system Help - Windows API.
Oto przykład utworzenia okna elementu steruj cego typu "Klawisz" itp. Kompilator zasobów generuje na podstawie tego "składu"
ko cowy plik aplikacji.
(BUTTON to nazwa typu):
------------------Plik MEDYT-01.H-------------------------------
hControlWnd = CreateWindow ("BUTTON", " Napis_na_Klawiszu ", #define szAppName "MEDYT-01"
BS_PUSHBUTTON |WS_CHILD | WS_VISIBLE, #define ID_EDIT 200
10, 20, 30, 40,
hWnd, ID_Elem, hInstance, 0); ------------------Plik główny: MEDYT-01.CPP---------------------
if(IDOK==MessageBox(0, "", "", MB_OK)) ... long FAR PASCAL WndProc (HWND, unsigned, WORD, LONG) ;
IDOK to predefiniowany w Windows identyfikator klawisza [OK]. int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance,
Oto krótkie wyja nienie pozostałych elementów: LPSTR lpszCmdLine, int nCmdShow)
{
10, 10, 30, 20, - współrz dne. x, y, szeroko , wysoko WNDCLASS wndClass;
hWnd, - oznacznik okna macie ystego MSG msg;
HWND hWnd;
Przesuwanie i zmiana wielko ci elementu steruj cego. RECT rect;
Gdy klasa zostanie zarejestrowana, ka de okno tej klasy b dzie InsertMenu(hMenu, IDM_R1, MF_BYCOMMAND |MF_DISABLED,
miało to samo menu, chyba e dostarczymy odpowiedni IDM_R5,
identyfikator menu w momencie tworzenia okna funkcj "Rozkaz 5");
CreateWindow(). InsertMenu(hMenu, 1, MF_ENABLED, IDM_R5, "Rozkaz 5");
- Drugim sposobem jest doł czenie menu w momencie tworzenia Funkcja wstawi za pozycj "Rozkaz 1" now pozycj "Rozkaz 5",
okna, wtedy tylko tworzone okno b dzie miało dane menu. jednocze nie ustawia jej status. Drug funkcj dodaj c pozycj
do utworzonego systemu menu jest:
Nale y najpierw załadowa menu przy u yciu funkcji LoadMenu(),
która zwraca jego identyfikator: AppendMenu(hMenu, MF_ENABLED, IDM_R4, "Rozkaz 4");
HMENU hMenu = LoadMenu(hInstance, "NazwaMenu"); Poni ej przykład zdefiniowania menu aplikacji w taki wła nie
sposób:
hWnd = CreateWindow(szAppName,
"Nazwa Aplikacji", case WM_CREATE:
WS_OVERLAPPEDWINDOW, hMenu = CreateMenu(); //Utworzenie menu
CW_USEDEFAULT, AppendMenu(hMenu, MF_ENABLED, IDM_R1, "Rozkaz 1");
CW_USEDEFAULT, AppendMenu(hMenu, MF_ENABLED, IDM_R2, "Rozkaz 2");
CW_USEDEFAULT, AppendMenu(hMenu, MF_ENABLED, IDM_R3, "Rozkaz 3");
CW_USEDEFAULT, SetMenu(hWnd, hMenu); //Wy wietlenie menu
NULL, ...
hMenu, <-- tu break;
hIstance,
NULL ); Usuwanie pozycji z menu mo na przeprowadzi dwoma sposobami:
Typow praktyk jest doł czenie pozycji menu do instrukcji - poprzez wskazanie numeru pozycji w systemie menu:
switch w funkcji okienkowej. Poniewa Windows wysyła komunikat
WM_COMMAND do odpowiedniej funkcji okienkowej w odpowiedzi na DeleteMenu(hMenu, 1, MF_BYPOSITION); //usuni ta zostanie druga
wybór pozycji przez u ytkownika, a parametr wParam zawiera //pozycja z systemu menu
identyfikator tej e pozycji - mo na napisa tak:
- przez wyszczególnienie identyfikatorem pozycji
case WM_COMMAND:
switch (wParam) DeleteMenu(hMenu, IDM_R3, MF_BYCOMMAND);
{
case IDM_R1: Po usuni ciu pozycji z menu Window usunie równie wszystkie
... obsługa ...; break; zwi zane z ni submenu.
case IDM_R2:
... obsługa ...; break Zaznaczanie pozycji w menu (mark).
case IDM_QUIT:
...DestroyWindow(...); Obok pozycji w menu mo na umie ci znak markuj cy ("ptaszek").
} Znak markuj cy mo na zainicjowa w pliku zasobów .RC. Dzi ki
temu, u ytkownik w momencie otwarcia okna dowie si z wygl du
Jak rozbudowuje si menu. menu o pocz tkowym ustawieniu opcji.
API Windows zawiera funkcje, umo liwiaj ce rozbudow menu nawet MENUITEM "Rozkaz 2", IDM_R2, CHECKED
w ruchu aplikacji (run-time). Rozbudowa menu w konkretnym oknie
nie poci ga za sob zmian w innych, opartych na tej samej klasie W trakcie pracy aplikacji nale y posłu y si funkcj
CheckMenuItem(). Zwykle najpierw kasujemy "ptaszka" przy
oknach. Jest to mo liwe, poniewa w chwili tworzenia okna poprzedniej pozycji:
otrzymuje ono swoj kopi menu (tradycyjne w C/C++ przekazywanie
CheckMenuItem( hMenu, IDM_R2, MF_UNCHECKED);
kopii zmiennej do funkcji). CheckMenuItem(hMenu, IDM_R3, MF_CHECKED);
Nie wszystkie pozycje w menu s w danym stadium pracy aplikacji Zmiany pozycji menu
132
BEGIN
Funkcja ModyfyMenu() pozwala na zmian nazwy pozycji i jej POPUP "&File"
atrybutów. Oto przykłady u ycia tej funkcji: BEGIN
MENUITEM "&Open", IDM_OPEN
ModifyMenu(hMenu, IDM_R2, MF_BYCOMMAND, IDM_R2, "Polecenie MENUITEM "&New" , IDM_NEW
2"); MENUITEM "&Save", IDM_SAVE
MENUITEM "Save &As", IDM_SAVEAS
Identyfikator pozycji nie ulegnie zmianie, jedynie nazwa pola z MENUITEM "&DOS shell", IDM_DOSSHELL
"Rozkaz 2" na "Polecenie 2". Mo emy zmieni jednocze nie i MENUITEM "E&xit", IDM_EXIT
identyfikator, by nie pomyli si w programie: END
POPUP "&Options"
ModifyMenu(hMenu, IDM_R2, MF_BYCOMMAND, IDM_P2, "Polecenie BEGIN
2"); MENUITEM "Menu&1", IDM_M1,
MENUITEM "Menu&2" , IDM_M2, CHECKED
Dodatkowo mo na ustawi za jednym zamachem i atrybuty: END
END
ModifyMenu(hMenu, IDM_R2, MF_BYCOMMAND | MF_CHECKED |
MF_GRAYED, ZASTOSOWANIE Resource Worshop
IDM_R2, "Polecenie 2"); Takie pliki zasobów w Borland C++ mało kto tworzy dzi "na
piechot ". BORLAND C++ oferuje do tego celu dwa
U ycie grafiki w systemie menu. narz dzia:
Edytor zasobów - Resource Workshop
W systemie menu aplikacji mo emy zamiast ła cucha znaków "Rozkaz Automatyczny generator - DialogExpert (wersje 4+)
2" umie ci element graficzny - np. w postaci mapy bitowej. Najwygodniejszym sposobem jest zastosowanie edytora zasobów
Zamiast pola o nazwie "Pole", wprowadza map bitow : Resource Workshop. Jest to tym wygodniejsze, e Resource
Workshop pozwala jednocze nie obserwowa i ródłowy plik *.RC
HMENU hMenu = GetMenu(hWnd); (ASCII) i efekt - menu w ruchu.
HBITMAP hBitmap = LoadBitmap (hIstance, "Pole"); W rodowisku Borland C++ okienka dialogowe tworzy si tak e
ModifyMenu(hMenu, IDM_R2, MF_BYCOMMAND | MF_BITMAP, zwykle przy pomocy Resource Worshop.
IDM_R2, Tworzenie okienek dialogowych przy pomocy Resource Workshop
(LPSTR) MAKELONG (hBitmap, 0)); przypomina składanie budowli z gotowych klocków.
GetMenu() zwraca oznacznik aktualnego menu, potrzebny jako Kolejne elementy steruj ce mo emy umieszcza w okienku
pierwszy parametr funkcji ModifyMenu(). Drugim parametrem tej dialogowym poprzez wybranie ich z palety narz dzi i
funkcji jest identyfikator pozycji, któr chcemy zmieni . przeniesienie do projektowanego okienka technik "poci gnij i
Trzecia okre la, e zmiana ma by wykonana przez wyszukanie upu " (drag & drop).
pozycji za po rednictwem jej identyfikatora oraz e now pozycj
Po skróconym omówieniu najwa niejszych funkcji z API Windows
ma reprezentowa mapa bitowa. Czwarty parametr okre la przejd my to niemniej krótkiej prezentacji zasad tworzenia
identyfikator nowej pozycji. Poniewa ostatnim parametrem nie aplikacji przy pomocy biblioteki obiektów OWL.
jest ju wska nik do ła cucha znakowego, nale y przesła
oznacznik mapy bitowej jako mniej znacz ce słowo tego parametru. [Z]
________________________________________________________________
W tym celu 16-bitowy oznacznik jest ł czony z 16-bitow stał , a 1. Przeanalizuj program w pełnej wersji (na dyskietce).
2. Zmodyfikuj dowoln aplikacj przykładow tak, by doł czy do
nast pnie poddawany konwersji do typu Long Pointer to STRing. niej inn ikon .
3. Opracuj własne menu i własn ikon przy pomocy Resource
Zmiana menu aplikacji na kolejne. Workshop.
________________________________________________________________
Aplikacja w ró nych stadiach pracy mo e mie na ekranie ró ne
(kilka czasem kilkana cie) menu. Wymiany menu w oknie aplikacji Krótka instrukcja do Resource Workshop.
mo na dokona , załadowuj c nowe menu funkcj LoadMenu() i
ustawiaj c je jako aktualne funkcj SetMenu(): ________________________________________________________________
Tworz c obiekt klasy TNaszProgram b dziemy wykorzystywa A oto p tla pobierania komunikatów w uproszczeniu. "Pump" to po
dziedziczenie od tej wła nie klasy bazowej: prostu "pompowanie" komunikatów (message) oczekuj cych (waiting)
class TNaszProgram : public TApplication w kolejce. PeekMessage() to sprawdzenie, czy w kolejce oczekuje
komunikat. PM_REMOWE to "brak komunikatu".
Podstawowym celem zastosowania tej wła nie klasy bazowej jest
odziedziczenie gotowej funkcji - metody virtual InitMainWindow() BOOL TApplication::PumpWaitingMessages()
{
(zainicjuj główne okno programu). Utworzenie obiektu klasy MSG msg;
TNaszProgram nast puje zwykle w czterech etapach: BOOL foundOne = FALSE;
* Windows uruchamiaj program wywołuj c główn funkcj WinMain() while (::PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
lub OwlMain() wchodz c w skład ka dej aplikacji. foundOne = TRUE;
* Funkcja WinMain() tworzy przy pomocy operatora new nowy obiekt if (msg.message == WM_QUIT)
{
- aplikacj . BreakMessageLoop = TRUE;
* Obiekt - aplikacja zaczyna funkcjonowa . Konstruktor obiektu MessageLoopResult = msg.wParam;
(własny, b d odziedziczony po klasie TApplication) wywołuje ::PostQuitMessage(msg.wParam);
funkcj - wirtualn metod InitMainWindow(). break;
* Funkcja przy pomocy operatora new tworzy obiekt - okno }
aplikacji.
if (!ProcessAppMsg(msg))
Wska nik do utworzonego obiektu zwraca funkcja GetApplication(). {
::TranslateMessage(&msg);
Dla zobrazowania mechanizmów poni ej przedstawiamy uproszczony ::DispatchMessage(&msg);
"wyci g" z dwu opisywanych klas. Nie jest to dokładna kopia kodu }
}
ródłowego Borlanda, lecz skrót tego kodu pozwalaj cy na return foundOne;
zrozumienie metod implementacji okienkowych mechanizmów wewn trz }
klas biblioteki OWL i tym samym wewn trz obiektów obiektowo - int TApplication::MessageLoop()
134
{ Metoda GetWindowClass() bardzo przypomina klasyczne
long idleCount = 0; zainicjowanie zanej ju struktury WNDCLASS:
MessageLoopResult = 0;
while (!BreakMessageLoop) { void TWindow::GetWindowClass(WNDCLASS& wndClass)
TRY { {
if (!IdleAction(idleCount++)) wndClass.cbClsExtra = 0;
::WaitMessage(); wndClass.cbWndExtra = 0;
if (PumpWaitingMessages()) wndClass.hInstance = *GetModule();
idleCount = 0; wndClass.hIcon = 0;
} wndClass.hCursor = ::LoadCursor(0, IDC_ARROW);
if (MessageLoopResult != 0) { wndClass.hbrBackground = HBRUSH(COLOR_WINDOW + 1);
::PostQuitMessage(MessageLoopResult); wndClass.lpszMenuName = 0;
break; wndClass.lpszClassName = GetClassName();
} wndClass.style = CS_DBLCLKS;
}) wndClass.lpfnWndProc = InitWndProc;
} }
BreakMessageLoop = FALSE;
return MessageLoopResult; Skoro te wszystkie "klocki" zostały ju zaimplementowane
} wewn trz definicji klas, nasze programy powinny tylko umiej tnie
wewn trz klasy TWindow tak: Konstruktor obiektu klasy TOkno powinien tylko przekaza
parametry konstruktorowi klasy bazowej - i ju .
TWindow::EvCreate(CREATESTRUCT far&)
{ class TOkno : public TApplication
SetupWindow(); {
return (int)DefaultProcessing(); public:
} TOkno(LPSTR name, HANDLE hInstance, HANDLE hPrevInstance,
LPSTR lpCmdLine, int nShow) : TApplication(name,
void TWindow::EvSize(UINT sizeType, TSize&) hInstance, hPrevInstance, lpCmdLine, nShow)
{ {
if (Scroller && sizeType != SIZE_MINIMIZED) return;
{ }
Scroller->SetPageSize(); virtual void InitMainWindow();
Scroller->SetSBarRange(); };
}
} Umie cili my w definicji klasy jeszcze jedn funkcj inicjuj c
główne okno aplikacji. Mo emy j zdefiniowa np. tak:
135
void InitMainWindow(){MainWindow = new TWindow(NULL, "Okno
void TOkno::InitMainWindow(void) PW2" );};
{ };
MainWindow = new (TWindow(0, "Napis - Tytul Okna"));
} int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
Działanie funkcji polega na utworzeniu nowego obiektu (operator {
new) klasy bazowej TWindow. Główne okno stanie si zatem TOkno OBIEKT("Okno PW2", hInstance, hPrevInstance,
obiektem klasy TWindow (Niektóre specyficzne aplikacje posługuj lpCmdLine, nCmdShow);
LPSTR p1 = "Jesli wybierzesz [Anuluj]\n- aplikacja nie
si okienkiem dialogowym jako głównym oknem programu. W takiej ruszy!";
sytuacji dziedziczenie powinno nast powa po klasie TDialog). LPSTR p2 = "START";
Konstruktorowi tego obiektu przekazujemy jako parametr napis,
który zostanie umieszczony w nagłówku głównego okna aplikacji. if (MessageBox(NULL, p1, p2, MB_OKCANCEL) == IDCANCEL)
Pierwszy argument (tu ZERO) to wska nik do macie ystego okna, MessageBox(NULL, "I juz..." , "KONIEC" , MB_OK);
poniewa w bardziej zło onych aplikacjach wyst puj okna else
macie yste (parent) i okna potomne (child). Okno macie yste to OBIEKT.Run();
zwykle obiekt klasy "główne okno" a okno potomne to najcz ciej return 0;
okienko dialogowe, b d okienko komunikatów. W tym przypadku }
wpisujemy zero, poniewa program nie posiada w tym stadium ________________________________________________________________
wcze niejszego okna macie ystego. Uwagi techniczne.
Pozostało nam jeszcze doda funkcj WinMain() i pierwszy program cie ki do katalogów:
..\INCLUDE;..\CLASSLIB\INCLUDE;..\OWL\INCLUDE;
obiektowy w wersji "Maszyna do robienia nic" jest gotów. ..\LIB;..\CLASSLIB\LIB;..\OWL\LIB;
Konsolidacja:
Listing . Obiektowa "Maszyna do robienia nic" Options | Linker | Settings: Windows EXE (typ aplikacji)
________________________________________________________________ Options | Linker | Libraries:
#define STRICT - Container class Libraries: Static (bibl. klas CLASSLIB)
#define WIN31 - OWL: Static (bibl. OWL statycze .LIB)
#include <owl.h> - Standard Run-time Lib: Static (bibl. uruchomieniowe .LIB)
class TOkno : public TApplication (.) None - oznacza adne (nie zostan doł czone);
{ (.) Static - oznacza statyczne .LIB
public: (.) Dinamic - oznacza dynamiczne .DLL
TOkno(LPSTR AName, HANDLE hInstance, HANDLE hPrevInstance, ________________________________________________________________
LPSTR lpCmdLine, int nCmdShow)
: TApplication(AName, hInstance, hPrevInstance, lpCmdLine, JAK ROZBUDOWYWA OBIEKTOWE APLIKACJE?
nCmdShow) {};
void InitMainWindow(){MainWindow = new TWindow(NULL, Name);}; Mimo całego uroku obiektowych aplikacji pojawia si tu wszak e
}; drobny problem. Skoro komunikacja klawiatura/myszka -> program
-> ekran nie odbywa si wprost, lecz przy pomocy wymiany danych
int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance, pomi dzy obiektami ró nych warstw - w jaki sposób (w którym
LPSTR lpCmdLine, int nCmdShow) miejscu programu) umie ci "zwyczajne" funkcje i procedury i jak
{
TOkno OBIEKT("Windows - Program PW1", hInstance, zorganizowa wymian informacji. "Zwyczajne" funkcje b d
hPrevInstance, lpCmdLine, nCmdShow); przecie wchodzi w skład roboczych cz ci naszych programów
OBIEKT.Run(); (Engine). Rozwa my to na przykładzie aplikacji reaguj cej na
return 0; naci ni cie klawisza myszki. Najbardziej istotny -
} "newralgiczny" punkt programu został zaznaczony w tek cie "<--
________________________________________________________________ TU". Od Windows przejmiemy obsług komunikatów
WM_LBUTTONDOWN,
Wykonanie takiej aplikacji przebiega nast puj co. Windows WM_RBUTTONDOWN. Aby wiedzie , w którym miejscu ekranu jest
wywołuj główn funkcj WinMain(), która przekazuje swoje kursor myszki, wykorzystamy informacje przenoszone przez
parametry do konstruktora klasy TOkno::TOkno(). Konstruktor parametr lParam.
przekazuje parametry do konstruktora klasy bazowej
TApplication(). Po skonstruowaniu obiektu w pami ci funkcja Rozpoczniemy tworzenie programu od zdefiniowania klasy.
wywołuje odziedziczon metod Run(). Funkcja Run() wywołuje
metody InitApplication() (zainicjuj aplikacj ) i InitInstance() #define WIN31
(zainicjuj dane wyst pienie programu). Metoda InitInstance() #define STRICT
wywołuje funkcj InitMainWindow(), która buduje główne okno #include <stdio.h>
aplikacji na ekranie. Po pojawieniu si okna rozpoczyna #include <string.h>
działanie p tla pobierania komunikatów (message loop). P tla #include <owl.h>
komunikatów działa a do otrzymania komunikatu WM_QUIT.
class TNAplikacja : public TApplication
Rozbudujmy aplikacj o okienko komunikatów. Zastosujemy do tego {
funkcj MessageBox(). Funkcja zostanie u yta nie jako metoda public:
(składnik obiektu), lecz jako "wolny strzelec" (stand alone TNAplikacja(LPSTR AName, HANDLE hInstance, HANDLE
function). hPrevInstance, LPSTR lpCmdLine, int nCmdShow) :
TApplication(AName, hInstance, hPrevInstance, lpCmdLine,
Listing B. Maszyna rozszerzona o okienka komunikatów. nCmdShow) {};
________________________________________________________________ virtual void InitMainWindow();
};
#define WIN31
#define STRICT Wykorzystamy okienko komunikatu do wiadomego zako czenia pracy
#include <owl.h> aplikacji. Klasa TApplication jest wyposa ona w metod
CanClose() (czy mo na zamkn ?) słu c do zamykania głównego
class TOkno : public TApplication okna aplikacji. Metoda została zaimplementowana tak:
{
public: BOOL TApplication::CanClose()
TOkno(LPSTR Nazwa, HANDLE hInstance, HANDLE hPrevInstance, {
LPSTR lpCmdLine, int nCmdShow) if (MainWindow)
: TApplication(Nazwa, hInstance, hPrevInstance, lpCmdLine, return (MainWindow->CanClose());
nCmdShow) {}; else
136
return (TRUE); ________________________________________________________________
}
B dzie nam wi c potrzebna własna wersja metody CanClose() i Komunikaty Windows mo emy wykorzysta w programie.
wska nik do obiektu MainWindow. Wska nik (typu far utworzony ...
przez składowe makro _FAR) wygenerujemy przy pomocy makra BOOL CanClose();
_CLASSDEF(nazwa_klasy): void WMLButtonDown(RTMessage Msg)= [WM_FIRST +
WM_LBUTTONDOWN];
_CLASSDEF(TGOkno) void WMRButtonDown(RTMessage Msg)= [WM_FIRST +
WM_RBUTTONDOWN];
Implementujemy teraz klas główne okno aplikacji. Jako klas };
bazow stosujemy TWindow.
Nasze Główne_Okno potrafi obsługiwa nast puj ce zdarzenia:
class TGOkno : public TWindow * Funkcja CanClose() zwróciła wynik TRUE/FALSE,
{ * Naci ni to lewy/prawy klawisz myszki.
public: Komunikat Msg zadeklarowany jako zmienna typu RTMessage jest w
TGOkno(PTWindowsObject AParent, LPSTR ATitle) klasie macie ystej TWindow wykorzystywany tak:
: TWindow(AParent, ATitle) {};
_CLASSDEF(TWindow)
Konstruktor tradycyjnie wykorzystujemy do przekazania parametrów
class _EXPORT TWindow : public TWindowsObject
do konstruktora klasy bazowej. PTWindowsObject AParent to {
wska nik (PoinTer) do obiektu "okno" a ATitle to string - tytuł. ...
protected:
Obsługa komunikatów kierowanych do tego okna mo e by virtual LPSTR GetClassName()
realizowana przy pomocy metod zaimplementowanych jako elemeny { return "OWLWindow"; }
składowe klasy Główne Okno - TGOkno. virtual void GetWindowClass(WNDCLASS _FAR & AWndClass);
Program graficzny powinien reagowa raczej na myszk ni na virtual void SetupWindow();
klawiatur . Windows rozpoznaj zdarzenia zwi zane z myszk i
generuj komunikaty o tych zdarzeniach. virtual void WMCreate(RTMessage Msg) = [WM_FIRST +
WM_CREATE];
Zdarzenia myszki (mouse events).
________________________________________________________________ virtual void WMMDIActivate(RTMessage Msg) =
[WM_FIRST + WM_MDIACTIVATE];
Komunikat Zdarzenie ...
________________________________________________________________ virtual void WMSize(RTMessage Msg) = [WM_FIRST + WM_SIZE];
WM_MOUSEMOWE - przesuni to myszk (wewn trz obszaru virtual void WMMove(RTMessage Msg) = [WM_FIRST + WM_MOVE];
roboczego - inside the client area - virtual void WMLButtonDown(RTMessage Msg) = [WM_FIRST +
ICA) WM_LBUTTONDOWN];
WM_LBUTTONDOWN - naci ni to LEWY klawisz myszki (ICA)
WM_LBUTTONDBLCLK - naci ni to dwukrotnie LEWY klaw. (ICA) Zwró uwag na notacj . Zamiast WM_CREATE pojawiło si [WM_FIRST
WM_LBUTTONUP - puszczono LEWY klawisz (ICA)
WM_RBUTTONDOWN - naci ni to PRAWY klawisz myszki (ICA) + WM_CREATE]. Komunikat WM_FIRST jest predefiniowany w
WM_RBUTTONDBLCLK - naci ni to dwukrotnie PRAWY klaw. (ICA) OWLDEF.H
WM_RBUTTONUP - puszczono PRAWY klawisz (ICA) i musi wyst pi w obiektowych aplikacjach w dowolnej klasie
WM_MBUTTONDOWN - naci ni to RODK. klawisz myszki (ICA) okienkowej, b d steruj cej (window class/controll class), która
WM_MBUTTONDBLCLK - naci ni to dwukrotnie ROD. klaw. (ICA)
WM_MBUTTONUP - puszczono RODKOWY klawisz (ICA) winna odpowiada na okre lony komunikat. Oto fragment pliku
WM_NCMOUSEMOVE - ruch myszki poza client area (NCA) OWLDEF.H zawieraj cy definicje stałych tej grupy:
WM_NLBUTTONDOWN - naci ni to LEWY klawisz myszki poza
obszarem roboczym - non-client area #define WM_FIRST 0x0000
(NCA) /* 0x0000- 0x7FFF window messages */
WM_NCLBUTTONDBLCLK - naci ni to dwukrotnie LEWY klaw. (NCA) #define WM_INTERNAL 0x7F00
WM_NCLBUTTONUP - puszczono LEWY klawisz (NCA) /* 0x7F00- 0x7FFF reserved for internal use */
WM_NCRBUTTONDOWN - naci ni to PRAWY klawisz myszki (NCA) #define ID_FIRST 0x8000
WM_NCRBUTTONDBLCLK - naci ni to dwukrotnie PRAWY klaw. /* 0x8000- 0x8FFF child id messages */
(NCA) #define NF_FIRST 0x9000
WM_NCRBUTTONUP - puszczono PRAWY klawisz (NCA) /* 0x9000- 0x9FFF notification messages */
WM_NCMBUTTONDOWN - naci ni to R. klawisz myszki (NCA) #define CM_FIRST 0xA000
WM_NCMBUTTONDBLCLK - naci ni to dwukrotnie RODK. klaw. /* 0xA000- 0xFFFF command messages */
(NCA) #define WM_RESERVED WM_INTERNAL - WM_FIRST
WM_LBUTTONUP - puszczono RODKOWY klawisz (NCA) #define ID_RESERVED ID_INTERNAL - ID_FIRST
________________________________________________________________ #define ID_FIRSTMDICHILD ID_RESERVED + 1
#define ID_MDICLIENT ID_RESERVED + 2
Nast pna tabelka zawiera (znacznie skromniejszy) zestaw #define CM_RESERVED CM_INTERNAL - CM_FIRST
komunikatów generowanych pod wpływem zdarze zwi zanych z
klawiatur . Cho by z wizualnego porównaia wielko ci tych tabel W tym momencie zwró my jeszcze uwag , e funkcje z grupy
wyra nie wida , e Windows znacznie bardziej "lubi " współprac MessageHandlers s typu void i zwykle s metodami wirtualnymi -
z myszk . przeznaczonymi "z definicji" do nadpisywania przez programistów
w klasach potomnych. Wszystkie te metody maj zawsze jedyny
Komunikaty Windows w odpowiedzi na zdarzenia zwi zane z argument - referencj do struktury TMessage zdefiniowanej
klawiatur . nast puj co:
_______________________________________________________________
Komunikat Zdarzenie struct TMessage
_______________________________________________________________ {
WM_KEYDOWN Naci ni to (jaki ) klawisz. HWND Receiver; //Identyfikator okna - odbiorcy
WM_KEYUP Puszczono klawisz. WORD Message; //sam komunikat
WM_SYSKEYDOWN Naci ni to klawisz "systemowy". union
WM_SYSKEYUP Puszczono klawisz "systemowy". {
WM_CHAR Kod ASCII klawisza. WORD WParam; //Parametr WParam stowarzyszony z
________________________________________________________________ //komunikatem; ALBO (dlatego unia!)
struct tagWP
Klawisz systemowy to np. [Alt]+[Esc], [Alt]+[F4] itp. {
137
BYTE Lo;
BYTE Hi; Wy wietlanie współrz dnych jakkolwiek warto ciowe z
} WP; dydaktycznego punktu widzenia jest mało interesuj ce. Pokusimy
union si o obiektow aplikacj umo liwiaj c odr czne rysowanie w
{ oknie (freehand drawing).
DWORD lParam;
struct tagLP
{ [!!!]UWAGA
WORD Lo; ________________________________________________________________
WORD Hi;
} LP; Pakiety Borland C++ 3..4.5 zawieraj wiele gotowych "klocków" do
};
long Result; wykorzystania. Oto przykład wykorzystania w pliku zasobów .RC
}; standardowego okienka wej ciowego (Input Dialog Box) i
standardowego okienka typu Plik (File Dialog Box):
Po tych wyja nieniach mo emy zaimplementowa poszczególne
funkcje. #include <windows.h>
#include <owlrc.h>
void TAplikacja::InitMainWindow()
{ rcinclude INPUTDIA.DLG
MainWindow = new (0, Name); rcinclude FILEDIAL.DLG
}
ROZKAZY MENU LOADONCALL MOVEABLE PURE DISCARDABLE
Je li wybrano klawisz [Yes] funkcja zwróci IDYES. Je li funkcja BEGIN
zwróciła IDYES - operator porównania zwróci TRUE (prawda) i ta POPUP "&File"
te warto zostanie zwrócona przez metod CanClose: BEGIN
MENUITEM "&New" CM_FILENEW
BOOL TMyWindow::CanClose() MENUITEM "&Open" CM_FILEOPEN
{ MENUITEM "&Save" CM_FILESAVE
return (MessageBox(HWindow, "Wychodzimy?", END
"Koniec", MB_YESNO | MB_ICONQUESTION) == IDYES); END
}
Takie menu mo na zastosowa w programie obiektowym umieszcaj c
Stosunkowo najciekawsza kombinacja odbywa si wewn trz handlera je w konstruktorze i dokonuj c nadpisania metody AssignMenu()
komunikatu WM_LBUTTONDOWN. Ze struktury komunikatów pobierana (przypisz menu):
jest zawarto młodszego słowa parametru lParam - Msg.LP.Lo i
starszego słowa Msg.LP.Hi. S to wzgl dne współrz dne graficzne TGOkno::TGOkno(PTWindowsObject AParent, LPSTR ATitle) :
kursora myszki (wzgl dem naro nika okna) w momencie naci ni cia TWindow(AParent, ATitle)
lewego klawisza myszki. Funkcja sprintf() zapisuje je w postaci {
dwu liczb dziesi tnych %d, %d do bufora znakowego char AssignMenu("ROZKAZY");
string[20]. Funkcja GetDC() (Get Device Context) okre la ...
kontekst urz dzenia (warstwa sterownika urz dzenia) i dalej }
obiekt mo e ju stosuj c funkcj kontekstow "czu si "
niezale ny od sprz tu. Dane te w postaci znakowej s pobierane [S]
przez funkcj kontekstow OutText() jako string a równocze nie rcinclude - doł cz zasoby
pobierane s w formie liczbowej: Msg.LP.Hi. Msg.LP.Lo, aby LOADONCALL - załaduj po wywołaniu
wyznaczy współrz dne tekstu na ekranie. Funkcja strlen() owlrc - zasoby biblioteki klas OWL
oblicza długo ła cucha znakowego - i to ju ostatni potrzebny
nam parametr. Gotowe "klocki" mo na wykorzysta nawet wtedy, gdy nie pasuj w
100%. Inne ni typowe odpowiedzi na wybór rozkazu implementujemy
void TMyWindow::WMLButtonDown(RTMessage Msg)
{ w programie głównym poprzez nadpisanie wirtualnej metody
HDC DC;
char string[20]; virtual void CMFileOpen(RTMessage msg) =
sprintf(string, "(%d, %d)", Msg.LP.Lo, Msg.LP.Hi); <-- TU [CM_FIRST + CM_FILEOPEN]
DC = GetDC(HWindow);
TextOut(DC, Msg.LP.Lo, Msg.LP.Hi, string, strlen(string)); TGOkno GOkno;
int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance, Funkcja MoweTo() powoduje przesuni cie kursora graficznego do
LPSTR lpCmdLine, int nCmdShow) aktualnej pozycji myszki (ju wzgl dnej - z uwzgl dnieniem dc)
{ bez rysowania linii. Flaga ButtnDown została ustawiona.
TNAplikacja OBIEKT("Rysownik. Prawy klawisz umozliwia wyjscie.", Rysowanie scedujemy na metod obsługuj c WM_MOUSEMOVE -
przesuni cie myszki.
hInstance, hPrevInstance, lpCmdLine, nCmdShow);
OBIEKT.Run(); void TGOkno::WMMouseMove(RTMessage Msg)
return (OBIEKT.Status); {
} if (ButtonDown)
LineTo(dc, Msg.LP.Lo, Msg.LP.Hi);
Nic specjalnie ciekawego nie dzieje si w funkcji inicjuj cej }
główne okno, ani w funkcji zamykaj cej aplikacj . Zmieniły si
tylko napisy w okienku komunikatów. Je li lewy klawisz jest naci ni ty - funkcja LineTo() b dzie
kre li lini do kolejnych punktów " ledz c" ruch myszki. Je li
void TNAplikacja::InitMainWindow() u ytkownik pu ci lewy klawisz - zerujemy flag stanu klawisza
{ ButtonDown <== FALSE.
MainWindow = new TGOkno(0, Name);
} void TGOkno::WMLButtonUp(RTMessage)
{
BOOL TGOkno::CanClose() if (ButtonDown) ButtonDown = FALSE;
{ }
return (MessageBox(HWindow, Ptr, "KONIEC",
MB_YESNO | MB_ICONQUESTION) == IDYES); Jak ju nabazgrzemy po ekranie, prawy klawisz umo liwi nam
} skasowanie zawarto ci przy pomocy InvalidateRect().
_CLASSDEF(TMyWindow)
class TMyWindow : public TWindow LEKCJA 48: O PAKIETACH BORLAND C++ 4/4.5.
{ ________________________________________________________________
public: Z tej lekcji dowiesz si , czy warto kupi nowsz wersj Borland
HDC dc; C++ 4/4.5 i jakie niespodzianki czekaj Ci po zamianie
BOOL ButtonDown; kompilatora na nowszy.
BOOL Flaga_Start; ________________________________________________________________
TMyWindow(PTWindowsObject AParent, LPSTR ATitle); Czy warto sprawi sobie BORLAND C++ 4/4.5 ?
//Konstruktor
Kilka słów o tym, co oferuje Borland w pakietach "Borland C++
virtual void WMLButtonDown(RTMessage Msg) 4/4.5" i jakie niespodzianki czekaj nowych u ytkowników przy
= [WM_FIRST + WM_LBUTTONDOWN]; instalacji i uruchamianiu.
virtual void WMLButtonUp(RTMessage Msg)
= [WM_FIRST + WM_LBUTTONUP]; Wymagania sprz towe i instalacja
virtual void WMMouseMove(RTMessage Msg)
= [WM_FIRST + WM_MOUSEMOVE]; Aby instalacja i u ytkowanie pakietu przebiegało poprawnie,
virtual void WMRButtonDown(RTMessage Msg) zaleca si nast puj c konfiguracj sprz tu:
= [WM_FIRST + WM_RBUTTONDOWN];
virtual BOOL CanClose(); Wymagania sprz towe Borland C++ 4.
}; ________________________________________________________________
Parametr minimum zalecane (pełna konfig.)
TMyWindow::TMyWindow(PTWindowsObject AParent, LPSTR ATitle) ________________________________________________________________
: TWindow(AParent, ATitle) * procesor 80386/33 MHZ 486 DX (lub 386 + 387)
{ * miejsce na dysku 8 MB 80 MB (bez kompresji)
ButtonDown = FALSE; * pami RAM 4 MB 8 MB i wi cej
} * system DOS 4.01 DOS 6.0...6.22
* MS Windows 3.1 Windows NT
void TMyWindow::WMLButtonDown(RTMessage Msg) ________________________________________________________________
{
if ( !Flaga_Start )
{
Flaga_Start = TRUE; //UWAGA: Cz ciowa instalacja Borland C++ 4.
SetCapture(HWindow); //Jesli zainicjujemy SetCapture() ________________________________________________________________
dc = GetDC(HWindow); //w konstruktorze - mamy caly ekran
} Konfiguracja Dysk
MoveTo(dc, Msg.LP.Lo, Msg.LP.Hi); ________________________________________________________________
ButtonDown = TRUE; 1. Kompilator BCC 16 bitowy (D+W) 9 MB
} 2. Kompilator BCC 32 bitowy (D+W) 13 MB
3. rodowisko IDE 16 bitowe 26 MB
void TMyWindow::WMMouseMove(RTMessage Msg) 4. rodowisko IDE 32 bitowe 30 MB
{ 5. Tylko dla DOS (minimum) 8 MB
if ( ButtonDown ) ________________________________________________________________
LineTo(dc, Msg.LP.Lo, Msg.LP.Hi); * D+W - dla DOS i Windows
}
Mo na próbowa zainstalowa Borland C++ 4 na małym dysku, mo na
void TMyWindow::WMLButtonUp(RTMessage) tak e ograniczy si do 4 MB RAM, ale generowanie 32-bitowych
{ aplikacji b dzie wtedy znacznie utrudnione a praca kompilatora
if (ButtonDown) ButtonDown = FALSE; wolniejsza. W przypadku stosowania kompresorów (np. SUPERSTOR,
} DOUBLE SPACE) nale y pami ta , e wtórna kompresja plików jest
mało skuteczna i dysk zgłaszany jako 80 MB mo e okaza si
void TMyWindow::WMRButtonDown(RTMessage) "ciasny".
{
InvalidateRect(HWindow, NULL, TRUE); Borland C++ 4 mo na instalowa z dyskietek, b d z CD-ROM.
ReleaseCapture(); Poniewa pakiet BC++ 4 jest "okienkowo - zorientowany", nawet
ReleaseDC(HWindow, dc); program instalacyjny wymaga obecno ci Windows. Uruchomienie
Flaga_Start = FALSE; programu instalacyjnego nast puje zatem z poziomu Mened era
} programów rozkazem File | Run... (w spolszczonej wersji Windows
- Plik | Uruchom...) lub z DOS-owskiego wiersza rozkazu:
void TNAplikacja::InitMainWindow()
{ C:\>WIN X:INSTALL
MainWindow = new TMyWindow(0, Name);
} Opcji jest troch wi cej - o najciekawszych z nich - kilka słów
poni ej.
BOOL TMyWindow::CanClose()
{ Warto zwróci uwag na tzw. "rozszerzenie dla Windows"
return (MessageBox(HWindow, Ptr, "KONIEC", (extention to MS Windows) - Win32s. W programie INSTALL.EXE do
MB_YESNO | MB_ICONQUESTION) == IDYES); zainstalowania tego pakietu (pakiet jest oryginalnym produktem
} Microsofta i wymaga 8 MB przestrzeni dyskowej) słu y opcja
[Install Win32s]. Najwa niejszy plik-driver instaluje si w
int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance, pliku SYSTEM.INI:
LPSTR lpCmdLine, int nCmdShow)
{ device=X:\WINDOWS\SYSTEM\WIN32S\W32S.386
TNAplikacja OBIEKT("Rysownik. Prawy klawisz umozliwia
wyjscie.", hInstance, hPrevInstance, Pozwala to na uruchamianie 32 - bitowych aplikacji pod Windows
lpCmdLine, nCmdShow); 3.1. Je li masz Windows NT - jest to zb dne - o ten "drobiazg"
OBIEKT.Run(); zadbał ju Microsoft.
140
konfliktów.
W przypadku instalacji w sieci, gdzie Windows zainstalowane s
na serwerze nale y pami ta , e BC++ 4 w trakcie instalacji Je li jest ju Borland Pascal 7...
modyfikuje nie tylko klasyczne parametry systemu:
Je li masz ju zainstalowany Borland Pascal 7 nale y pami ta ,
FILES=40 e poprawna praca obu kompilatorów w jednym systemie wymaga
BUFFERS=40 "uregulowania stosunków":
PATH=...;X:\BC4\BIN;
1. Ka dy kompilator musi mie własn kopi debuggera TDW. Aby
ale tak e pliki konfiguracyjne i inicjacyjne w katalogu WINDOWS: unikn konfliktu pascalowski debugger mo na przemianowa np.:
W skład pakietu wchodz mi dzy innymi: BC++ 3/3.1 lub Turbo C++. I tu tak e czychaj pewne
niebezpiecze stwa. Stare projekty - tradycyjnie .PRJ w BC++ 4
* BCW - zintegrowane rodowisko (IDE) dla rodowiska Windows zyskuj nowe domy lne rozszerzenie .IDE. W okienku dialogowym
* TDW - Turbo Debugger for Windows zarz dzania projektem: Project | Open... przy pomocy opcji
* BCC - kompilator uruchamiany z DOS'owskiego wiersza rozkazu
* BCC32 - kompilator 32 - bitowy (odpowiednik BCC) [3.1 Project Files (*.prj)]
* BRCC - kompilator zasobów do kompilacji plików *.RC z zasobami
mo na dokona automatycznej konwersji do formatu .IDE, przy czym
do postaci binarnej *.RES
* RLINK - konsolidator słu cy do doł czania plików z zasobami stara wersja pliku *.PRJ pozostanie bez zmian. Niektóre stare
przy tworzeniu plików wykonywalnych *.EXE kody ródłowe b d wymaga drobnych modyfikacji. Szczególnie
* TLINK - "zwykły" konsolidator nale y zwró i uwag na:
* MAKE - program narz dziowy do automatyzacji kompilacji i
konsolidacji, korzystaj cy z tzw. plików instrukta owych - nakładki (overlay support)
(emuluj cy NMAKE Microsofta) - zarz dzanie pami ci (new - delete)
* WINSIGHT - przegl danie informacji o okienkach (dla Windows) i - informacje diagnostyczne w plikach (debug info)
- zmianne pseudorejestrowe (dost pne teraz tylko w niektórych
komunikatach trybach)
* TDUMP - bezpo rednie przegl danie informacji zawartych w
plikach *.EXE i *.OBJ O bibliotece Turbo Vision.
* TDSTRIP - narz dzie do usuwania tablicy symboli z plików
wykonywalnych Biblioteka Turbo Vision Library - TV.LIB współpracuj ca
* IMPLIB - importer bibliotek z DLL poprawnie z BC++ 3.0/3.1 powinna zosta powtórnie skompilowana,
* TDMEM - wy wietlanie informacji o zaj to ci pami ci poniewa BC++ 4 stosuje inny format:
* MAKESWAP - zarz dzanie swapowaniem (tworzenie plików
tymczasowych EDPMI.SWP o zadanej wielko ci) - informacji diagnostycznych (debug info format)
- inn długo identyfikatorów (symbol length)
i jeszcze par narz dzi (np. tradycyjny bibliotekarz TLIB, - inn bibliotek Runtime Library
TOUCH, GREP, itp.), o których tu nie wspominam.
Kod ródłowy biblioteki znajduje si w katalogu:
Czego robi nie nale y?
\BIN\TVISION\SOURCE
Przede wszystkim nie nale y traktowa Borland C++ 4/4.5 jako
"upgrade" do wcze niejszych wersji (3, czy 3.1). W kompilatorze Po (Uwaga!) wprowadzeniu kilku niewielkich zmian
dokonano sporych zmian (np. inaczej działa operator new). Nie
wolno zatem "nadpisa " zawarto ci poprzednich katalogów i plików - do plików ródłowych .CPP
- do pliku instrukta owego MAKEFILE
o tych samych nazwach. Szczególnie dotyczy to plików
konfiguracyjnych BCCONFIG.BCW i TDCONFIG.TDW. Je li stare wersje oraz po skompilowaniu przy pomocy BCC 4 w DWU WERSJACH: TVO.LIB
(z nakładk - Overlay) i TVNO.LIB (bez nakładki - No Overlay)
tych plików nie zostan przemianowane, b d usuni te z pola biblioteka TVL mo e by nadal z powodzeniem stosowana z Borland
widzenia (PATH) - pojawi si konflikty przy uruchamianiu BC++. C++ 4. Podobnie rekompilacji wymaga bibiloteka klas doł czona w
wersji ródłowej w katalogu X:\BC4\SOURCE\CLASSLIB.
Ze wzgl du na wprowadzone zmiany pliki .OBJ tworzone przez
wcze niejsze kompilatory C b d w zasadzie przeno ne, natomiast O AUTOMATYZACJI - CASE.
pliki .OBJ i biblioteki utworzone przez wcze niejsze wersje
kompilatorów C++ (szczególnie Borland C++ 3.1) b d sprawia Prócz znanego ju od do dawna (w komputerologii kilka lat to
kłopoty (nie b d np. poprawnie wywoływane destruktory). Przy cała epoka) tradycyjnego narz dzia Resource Worshop, w wersji
konsolidacji "starych" plików mo na stosowa opcj -K2 BC4 wyst puj jeszcze inne narz dzia CASE kategorii "wizard"
konsolidatora, co pozwoli zmniejszy do minimum ryzyko (kreator aplikacji):
141
oraz nowoczesnych styli programowania:
- ClassExpert obiektowego i zdarzeniowego
- ApplicationExpert pozostał Ci ju tylko wykonanie trzech rzeczy. Powiniene teraz:
- DialogExpert
- TargetExpert
1. Pisa własne aplikacje
Nazwa TargetExpert pochodzi od ang. "Target platform" - docelowa 2. Pisa własne aplikacje
3. Pisa własne aplikacje
platforma pracy aplikacji (DOS, Win16, Win32).
Biblioteka OWL 2.0 została wzbogacona o dodatkowe klasy VBX Tak naprawd - jest to jedyny sposób, by zosta dobrym
umo liwiaj ce współprac z Visual Basic i wykorzystanie programist .
elementów utworzonych przy pomocy VB.
Wspomaganie tworzenie programu przy pomocy tych narz dzi Przez pewien czas oka e Ci si zapewne przydatna dyskietka
(AppExpert podobnie jak inne narz dzie typu Wizard jest doł czona do ksi ki. Znajdziesz tam jeszcze sporo programów
automatycznym generatorem aplikacji) wymaga od u ytkownika przykładowych, które nie zmie ciły si w ksi ce.
wyboru z listy "zagadnienia" a z okienek docelowych cech
programu. Przytocz tu dla przykładu list opcji z pojedynczego Przyjemnej pracy z programem MEDYT.
okienka AppExperta z krótkim wyja nieniem:
________________________________________________________________
Topics: (okienko z list : Zagadnienia)
Application (program docelowy)
-- Basic Opttions (wybór opcji podstawowych)
-- Advanced Options (opcje zaawansowane)
-- Code Gen Control (sposób generacji kodu)
-- Admin Options (opcje "administracyjne")
Main Window (główne okno programu)
-- Basic Options (podstawowe opcje)
-- SDI Client (interf. jednego dokumentu)
-- MDI Client (interf. wielu dokumentów)
MDI Child/View (okna potomne, widok/edycja)
-- Basic Options (opcje podstawowe)
Features: (cechy)
[.] SpeedBar (ma pasek narz dzi)
[.] Status line (ma wiersz statusowy)
[.] Drag/drop (obsługuje ci gnij/upu )
[.] Printing (obsługuje drukark )
________________________________________________________________
ZAKO CZENIE.