Cyfroteka.pl

klikaj i czytaj online

Cyfro
Czytomierz
00099 007733 10468433 na godz. na dobę w sumie
C++Builder 6. Ćwiczenia - książka
C++Builder 6. Ćwiczenia - książka
Autor: Liczba stron: 128
Wydawca: Helion Język publikacji: polski
ISBN: 83-7197-986-X Data wydania:
Lektor:
Kategoria: ebooki >> komputery i informatyka >> programowanie >> c++ builder - programowanie
Porównaj ceny (książka, ebook, audiobook).
Borland C++ Builder to jedno z najwygodniejszych środowisk programistycznych dla programistów C++, platforma ciesząca się dużą popularnością i mająca za sobą długą historię. W języku C++ napisano wiele aplikacji dla Windows, z których znaczna część powstała właśnie w Builderze.

'C++ Builder. Ćwiczenia' to uzupełnienie poprzedniej publikacji Wydawnictwa Helion, zatytułowanej 'C++ Builder 5. Ćwiczenia praktyczne'. Książka omawia zmiany, jakie wprowadzono w nowej, szóstej już wersji C++ Buildera, a także porusza wiele zagadnień, które nie znalazły się w książce traktującej o poprzedniej edycji tego programu. Informacje zostały przekazane w formie ćwiczeń z dokładnym omówieniem prezentowanego kodu źródłowego.

Znajdziesz w niej między innymi:

Znajdź podobne książki Ostatnio czytane w tej kategorii

Darmowy fragment publikacji:

C++Builder 6. Æwiczenia Autor: Andrzej Daniluk ISBN: 83-7197-986-X Format: B5, stron: 128 Przyk³ady na ftp: 1391 kB Borland C++ Builder to jedno z najwygodniejszych ġrodowisk programistycznych dla programistów C++, platforma ciesz¹ca siê du¿¹ popularnoġci¹ i maj¹ca za sob¹ d³ug¹ historiê. W jêzyku C++ napisano wiele aplikacji dla Windows, z których znaczna czêġæ powsta³a w³aġnie w Builderze. „C++ Builder. Æwiczenia” to uzupe³nienie poprzedniej publikacji Wydawnictwa Helion, zatytu³owanej „C++ Builder 5. Æwiczenia praktyczne”. Ksi¹¿ka omawia zmiany, jakie wprowadzono w nowej, szóstej ju¿ wersji C++ Buildera, a tak¿e porusza wiele zagadnieñ, które nie znalaz³y siê w ksi¹¿ce traktuj¹cej o poprzedniej edycji tego programu. Informacje zosta³y przekazane w formie æwiczeñ z dok³adnym omówieniem prezentowanego kodu ĥród³owego. Znajdziesz w niej miêdzy innymi: • Zagadnienia zwi¹zane z kompatybilnoġci¹ pomiêdzy wersjami pi¹t¹ i szóst¹ C++ Buildera • Seriê æwiczeñ przybli¿aj¹cych jêzyk C++ • Omówienie ġrodowiska IDE C++ Builder • Æwiczenia z programowania w C++ z wykorzystaniem C++ Builder • Æwiczenia z pisania aplikacji wielow¹tkowych • Sposoby tworzenia w³asnych komponentów IDZ DO IDZ DO PRZYK£ADOWY ROZDZIA£ PRZYK£ADOWY ROZDZIA£ SPIS TREĎCI SPIS TREĎCI KATALOG KSI¥¯EK KATALOG KSI¥¯EK KATALOG ONLINE KATALOG ONLINE ZAMÓW DRUKOWANY KATALOG ZAMÓW DRUKOWANY KATALOG TWÓJ KOSZYK TWÓJ KOSZYK DODAJ DO KOSZYKA DODAJ DO KOSZYKA CENNIK I INFORMACJE CENNIK I INFORMACJE ZAMÓW INFORMACJE ZAMÓW INFORMACJE O NOWOĎCIACH O NOWOĎCIACH ZAMÓW CENNIK ZAMÓW CENNIK CZYTELNIA CZYTELNIA FRAGMENTY KSI¥¯EK ONLINE FRAGMENTY KSI¥¯EK ONLINE Wydawnictwo Helion ul. Chopina 6 44-100 Gliwice tel. (32)230-98-63 e-mail: helion@helion.pl Spis treści Wstęp...................................................z...................................................z.................... .................................... 5 Rozdział 1. Konfiguracja projektu ...................................................z.........................................................................7 Kompatybilność wersji Buildera ...................................................l...............................................8 Podsumowanie ...................................................l...................................................l.......................9 Rozdział 2. C++ w pigułce...................................................z...................................................z...................................... 11 Pliki nagłówkowe ...................................................l...................................................l.................11 Przestrzenie nazw standardowych...................................................l...........................................14 Klasy wejścia-wyjścia języka C++ ...................................................l.........................................14 Obsługa plików z wykorzystaniem klasy ios...................................................l....................17 Struktury w C++...................................................l...................................................l...................18 Samodzielne tworzenie plików nagłówkowych...................................................l................21 Klasy w C++ ...................................................l...................................................l........................22 Konstruktor i destruktor ...................................................l...................................................l.27 Inne spojrzenie na klasy. Własności ...................................................l.................................29 Funkcje przeładowywane ...................................................l...................................................l.....31 Niejednoznaczność ...................................................l...................................................l........33 Funkcje ogólne ...................................................l...................................................l.....................34 Przeładowywanie funkcji ogólnych ...................................................l..................................36 Typ wyliczeniowy ...................................................l...................................................l................37 Dziedziczenie ...................................................l...................................................l.......................38 Funkcje wewnętrzne...................................................l...................................................l.............42 Realizacja przekazywania egzemplarzy klas funkcjom ...................................................l..........43 Tablice dynamicznie alokowane w pamięci...................................................l............................45 Tablice otwarte ...................................................l...................................................l.....................48 Wskaźniki do egzemplarzy klas ...................................................l..............................................50 Wskaźnik this ...................................................l...................................................l.......................51 Obsługa wyjątków...................................................l...................................................l................52 Podsumowanie ...................................................l...................................................l.....................56 Rozdział 3. Środowisko programisty — IDE...................................................z................................................... 57 Biblioteka VCL ...................................................l...................................................l....................59 Karta Standard ...................................................l...................................................l...............59 Karta Additional...................................................l...................................................l.............61 Karta Win32...................................................l...................................................l...................63 Karta System ...................................................l...................................................l..................65 Karta Dialogs ...................................................l...................................................l.................66 4 C++Builder 6. Ćwiczenia Biblioteka CLX ...................................................l...................................................l....................67 Karta Additional...................................................l...................................................l.............67 Karta Dialogs ...................................................l...................................................l.................68 Podsumowanie ...................................................l...................................................l.....................68 Rozdział 4. C++ w wydaniu Buildera 6...................................................z............................................................. 69 Formularz ...........................................l...................................................l.....................................69 Zdarzenia ...................................................l...................................................l..............................71 Rzutowanie typów danych ...................................................l...................................................l...78 Klasa TObject...................................................l...................................................l.......................78 Wykorzystujemy własne funkcje ...................................................l............................................79 Wykorzystujemy własny, nowy typ danych ...................................................l...........................81 Widok drzewa obiektów — Object Tree View ...................................................l.......................84 Komponenty TActionManager i TActionMainMenuBar ...................................................l.84 Typy wariantowe...................................................l...................................................l..................89 Tablice wariantowe ...................................................l...................................................l........91 Klasy wyjątków...................................................l...................................................l....................93 Więcej o wskaźniku this...................................................l...................................................l.......96 Podsumowanie ...................................................l...................................................l.....................98 Rozdział 5. Biblioteka CLX ...................................................z...................................................................................... 99 Komponenty TTimer i TLCDNumber ...................................................l....................................99 Podsumowanie ...................................................l...................................................l...................103 Rozdział 6. Tworzymy własne komponenty ...................................................z................................................... 105 Podsumowanie ...................................................l...................................................l...................110 Rozdział 7. Aplikacje wielowątkowe ...................................................z................................................................111 Funkcja BeginThread() ...................................................l...................................................l......111 Komponent TChart...................................................l...................................................l.............114 Podsumowanie ...................................................l...................................................l...................116 Rozdział 8. C++Builder jako wydajne narzędzie obliczeniowe...................................................z.......... 119 Obliczenia finansowe ...................................................l...................................................l.........119 Podsumowanie ...................................................l...................................................l...................126 Rozdział 2. C++ w pigułce Ten rozdział poświęcony jest skrótowemu omówieniu podstawowych pojęć, którymi po- sługujemy się tworząc programy w C++. Zagadnienia tutaj poruszane posiadają kluczowe znaczenie dla zrozumienia idei programowania zorientowanego obiektowo w środowisku C++. Używana terminologia oraz zamieszczone w dalszej części rozdziału przykłady (o ile nie zostały użyte elementy z biblioteki VCL) zgodne są ze standardem ANSI X3J16/ISO WG21 języka C++1. Pliki nagłówkowe W odróżnieniu od programów pisanych w standardowym języku C, gdzie nie musimy zbytnio przejmować się dołączaniem do kodu źródłowego wielu plików nagłówkowych, w programach C++ nie można ich pominąć. Wynika to z faktu, iż bardzo wiele funkcji bibliotecznych korzysta z własnych struktur oraz typów danych. W C++ ich definicje znajdują się właśnie w plikach nagłówkowych (ang. header files), które posiadają stan- dardowe rozszerzenie .h. C++ jest językiem bazującym na funkcjach, dlatego do pliku źródłowego programu musimy włączyć przy pomocy dyrektywy KPENWFG odpowiednie pliki zawierające wywoływane funkcje wraz z ich protaotypami. Większość standardowych plików nagłówkowych znajduje się w katalogu instalacyjnym INCLUDE. W dalszej części rozdziału wiadomości na temat praktycznego wykorzystania zarówno standardowych, jak i samodzielnie tworzonych plików nagłówkowych znacznaie rozszerzymy. Prosty przykład wykorzystania standardowych plików nagłówkowych iostream.h (zawiera definicje klas umożliwiające wykonywanie różnorodnych operacji wejścia-wyjścia na strumieniach) oraz conio.h (zawiera funkcje obsługi ekranu) zawiera poniższe ćwiczenie. 1 Musimy zauważyć, iż Borland C++Builder traktowany jwako kompletne środowisko programistyczne z pewnych względów nie spełnia wymogów ISO. 12 Ćwiczenie 2.1. C++Builder 6. Ćwiczenia 1. Stwórzmy na dysku odrębny katalog (folder) nazywając go apo prostu . W katalogu tym przechowywane będą wszystkie pliki wykorzystywanae przez aktualnie pisany program. 2. Uruchamiamy C++Buildera 6. Poleceniem menu FileNewOtherConsole Wizard otwórzmy nowy moduł. W okienku dialogowym Console Wizard w opcji Source Type wybierzmy C++, zaś w drugim panelu odznaczmy Use VCL, Use CLX, Multi Thread oraz wybierzmy Console Application, tak jak pokazuje to rysunek 2.1. Zaznaczenie tej opcji powoduje, że program będzie traktował główany formularz tak, jakby był normalnym okienkiem tekstowym. Pozostawienie aktywneja opcji Use CLX (CLX jest skrótem od angielskiego terminu, określającego pewnąa klasę bibliotek wspomagających proces projektowania aplikacji przenośnych pomiędzya Windows a Linux: Cluster software runing under LinuX) spowoduje automatyczne dołączenie do programu plikau nagłówkowego clx.h wspomagającego tworzenie aplikacji międzyplatformowyach. Rysunek 2.1. Okno Console Wizard 3. Potwierdzając przyciskiem OK przechodzimy do okna zawierającego szkielet kodu przyszłego programu, tak jak pokazuje to rysunek 2.2. Rysunek 2.2. Kod modułu Unit1.cpp 4. Programów naszych nie będziemy uruchamiać z linii poleaceń, dlatego okno edycji kodu wypełnimy tekstem pokazanym na wydruku 2.1. Nastęapnie poleceniem FileSave As… zapiszemy nasz moduł w katalogu 01 jako 7PKVERR. Projekt modułu zapiszemy poleceniem FileSave Project As… w tym samym katalogu:  2TQLGMVADRT. Rozdział 2. (cid:1) C++ w pigułce 13 Wydruk 2.1. Kod modułu Unit01.cpp projektu Projekt_01.bpr KPENWFGKQUVTGCOJ KPENWFGEQPKQJ RTCIOCJFTUVQR KPVOCKP ] ENTUET  EQWV KGēFQDT[GPFN IGVEJ  TGVWTP _ 5. Po uruchomieniu programu poleceniem RunRun (F9), na ekranie w okienku udającym tryb tekstowy Windows pojawi się napis powitania. Program opuszczamy naciskając klawisz Enter. Jak widać, w skład tego programu wchodzą dwa pliki nagłówkowe: iostream.h oraz conio.h. Pierwszy z nich zdefiniowany jest w C++ i umożliwia wykonywanie szeregu operacji wejścia-wyjścia. Powodem włączenia pliku conio.h jest zastosowanie funkcji ENTUET (ang. clear screen) czyszczącej ekran tekstowy oraz funkcji IGVEJ (ang. get character) oczekującej na naciśnięcie dowolnego klawisza (wprowadzenie dowolnego znaku). Użycie dyrektywy RTCIOCJFTUVQR (ang. header stop) informuje kompilator o końcu listy plików nagłówkowych. Każdy program pisany w C++ musi zawierać przynajmniej ajedną funkcję. Główna funkcja OCKP jest tą, która zawsze musi istnieć w programie i zawsze wywoływana jest jako pierw- sza. Zestaw instrukcji właściwych danej funkcji musi być zawarty w nawiasach klamro- wych ]_, będących swojego rodzaju odpowiednikiem DGIKPGPF w Pascalu. Instrukcje zawarte w nawiasach klamrowych nazywamy wblokiem instrukcji (ang. code block); jest on grupą logicznie powiązanych ze sobą elementów wtraktowanych jako niepodzielny fragment programu. Każda funkcja określonego typu powinna zwracać wartość tego samego typu. W powyższym przykładzie funkcja OCKP jest typu całkowitego KPV, zatem musi zwrócić do systemu taką samą wartość. Tutaj wykonaliśmy tę operację używając instrukcji TGVWTP, która jest niczym innym, jak jedną z możliwych wartości powrotnych udostępnianych w następ- stwie wywołania funkcji KPV OCKP . Jeżeli funkcja byłaby typu nieokreślonego, czyli XQKF (tzw. typ pusty, pusta lista parametrów), wówczas nie musielibyśmy zwracać do sys- temu żadnej wartości, tak jak ilustruje to poniższy przykład: XQKFOCKP ] ENTUET  EQWV KGēFQDT[GPFN IGVEJ  TGVWTP _ Brak wartości zwracanej przez funkcję XQKFOCKP w powyższym przykładzie wynika z faktu, że w programach C++ nieokreślona wartość funkcji (lub pusta lista parametrów) równoznaczna jest ze słowem XQKF. 14 C++Builder 6. Ćwiczenia W języku C++ słowo EQWV identyfikuje ekran (ale nie formularz !), zaś wraz z operatorem  pozwala wyprowadzić zarówno łańcuchy znaków, jak i zmienne wszystkich typów. Słowo GPFN (ang. end of line) odpowiada wysłaniu kombinacji znaków 4.( ustawiających kursor na początku następnego wiersza. Przestrzenie nazw standardowych Studiując niektóre programy C++ możemy zauważyć, iż przed słowami EQWV i GPFN może występować słowo UVF. Informuje ono kompilator o potrzebie korzystania z tzw. wy- znacznika przestrzeni nazw. Chodzi o to, aby kompilator wiedział, że używamy strumieni EQWV i GPFN z biblioteki standardowej: KPENWFGKQUVTGCOJ KPVOCKP ] WUKPIUVFEQWV WUKPIUVFGPFN EQWVVGMUVGPFN  _ Często też programiści, w celu uniknięcia niedogodności pisania UVF przed każdym EQWV i GPFN, po prostu informują kompilator o potrzebie używania acałej przestrzeni nazw standardowych, tj. że każdy obiekt, który nie zostanie oznaczony, z założenia będzie po- chodził z przestrzeni nazw standardowych. W tym przypadku, zamiast konstrukcji WUKPI UVFEQWV piszemy po prostu WUKPIPCOGURCEGUVF. KPENWFGKQUVTGCOJ KPVOCKP ] WUKPIPCOGURCEGUVF EQWVVGMUVGPFN  _ W książce tej nie będziemy jawnie rozróżniać przestrzeani nazw standardowych. Klasy wejścia-wyjścia języka C++ Język C++ posługuje się kilkoma predefiniowanymi łańcuchami wejścia-wyjścia. Dwa najbardziej podstawowe z nich, związane ze standardowym wejściem-wyjściem, to EQWV oraz EKP. Z pierwszym z nich zapoznaliśmy się już wcześniej. Słowo EKP wraz z operato- rem pozwala wprowadzać zarówno łańcuchy znaków, jak i raóżnego rodzaju zmienne. Oprócz opisanych predefiniowanych łańcuchów, w C++ zdefiniowany jest jeszcze szereg tzw. klas strumieni wejścia-wyjścia. Trzy podstawowe aklasy wejścia-wyjścia to: Rozdział 2. (cid:1) C++ w pigułce 15 (cid:1) QHUVTGCO (ang. output file stream) — wyprowadzanie danych, KHUVTGCO (ang. input file stream) — wprowadzanie danych, HUVTGCO (ang. file stream) — wprowadzanie i wyprowadzanie danych. (cid:1) (cid:1) Dwa proste ćwiczenia pozwolą nam zapoznać się z właśaciwościami wymienionych klas. Ćwiczenie 2.2. Zaprojektujemy program, którego jedynym zadaniem będzie odczytanie swojego własnego tekstu źródłowego zawartego w pliku .cpp i wyświetlenie go na ekranie. Kod tego pro- gramu, korzystającego z uniwersalnej klasy HUVTGCO, pokazany jest na wydruku 2.2. Wydruk 2.2. Moduł Unit02.cpp projektu Projekt_02.bpr KPENWFGKQUVTGCOJ KPENWFGHUVTGCOJ KPENWFGEQPKQJ RTCIOCJFTUVQR KPVOCKP ] EJCTDWHQT=? HUVTGCO+P(KNG ENTUET  +P(KNGQRGP 7PKVERR  YJKNG +P(KNGGQH ] +P(KNGIGVNKPG DWHQTUKGQH DWHQT  EQWVDWHQTGPFN _ +P(KNGENQUG  IGVEJ  TGVWTP _ Wykorzystanie omawianych na początku niniejszego podrozdziału klas wejścia-wyjścia wymaga włączenia do programu pliku nagłówkowego fstream.h, tak jak wykonaliśmy to w linii 2. programu. Dane z pliku będziemy wczytywać znak po znaku, zatem wymagane jest zadeklarowa- nie w linii 7. programu bufora danych typu znakowego EJCT o odpowiednim rozmiarze. Chociaż budowę klas i różne aspekty ich wykorzystywania omówimy dokładniej w dalszej części rozdziału, jednak już w tym miejscu zaczniemy posługiwać się odpo- wiednią terminologią. Omawiając deklarację z linii 8. w sposób tradycyjny, powiedzie- libyśmy, iż została tam zadeklarowana zmienna +P(KNG typu HUVTGCO. Jednak w odnie- sieniu do klas wygodniej jest posługiwać się innym sformułowaniem — powiemy, że w linii 8. programu zadeklarowaliśmy egzemplarz +P(KNG klasy HUVTGCO (bardzo często używa się też sformułowania, że został utworzony strumaień wejściowy +P(KNG). Jak zapewne wiesz, każdy plik, którego zawartość chcemy w odpowiedni sposób wy- świetlić, musi być najpierw otwarty do czytania. Czynność tę wykonujemy w linii 9. poprzez odwołanie się do egzemplarza (obiektu) klasy HUVTGCO z jawnym wskazaniem 16 C++Builder 6. Ćwiczenia funkcji, jakiej ma używać do otwarcia pliku. W terminologii stosowanej w programowaniu zorientowanym obiektowo powiemy, iż strumień wejściowy +P(KNG połączyliśmy z pli- kiem dzięki wywołaniu funkcji składowej klasy (metody) QRGP , której argumentem jest nazwa pliku umieszczona w podwójnych apostrofach. W przypadku, gdy czytany plik nie znajduje się w aktualnym katalogu, należy podać pełną ścieżkę dostępu według następującego przepisua: +P(KNGQRGP E EYDKNFA MQF[  7PKVERR  Proces czytania i wyświetlania na ekranie zawartości pliku wykonywany jest w liniach 11. – 14. przy pomocy instrukcji iteracyjnej YJKNG, która będzie wykonywana do czasu napotkania znacznika końca pliku. Osiągnięcie końca pliku wykrywamy za pomocą funkcji składowej GQH (ang. end of file). W linii 12. przy pomocy dwuparametrowej funkcji składowej IGVNKPG wczytujemy za- wartość pliku do bufora. Pierwszym parametrem tej funkcji jest zmienna DWHQT identyfi- kująca bufor danych wejściowych. Drugim parametrem jest jednoargumentowy operator czasu kompilacji UKGQH udostępniający długość zmiennej DWHQT. Operator ten wykorzy- stujemy w przypadku, gdy wymagamy, aby kod źródłowy programu był w dużej mierze przenośny, tzn. by można było wykorzystywać go na różnego rodzaju komputerach. Bar- dzo często warunek przenośności kodu wymaga, aby ustalić rzeczywistą długość da- nych, np. typu EJCT. W linii 15. wywołujemy funkcję składową ENQUG zamykającą otwarty uprzednio plik. Ćwiczenie 2.3. Obecne ćwiczenie ilustruje sposób posługiwania się klasami QHUVTGCO oraz KHUVTGCO. Poprzedni program został zmodyfikowany w taki sposób, aby po utworzeniu w aktual- nym katalogu nowego pliku można było zapisać w nim odpowiednie dane, którymi w tym przypadku są wartości funkcji UKP (sinus), której prototyp znajduje się w pliku nagłów- kowym math.h. Wydruk 2.3. Moduł Unit03.cpp projektu Projekt_03.bpr KPENWFGKQUVTGCOJ KPENWFGHUVTGCOJ KPENWFGOCVJJ KPENWFGEQPKQJ RTCIOCJFTUVQR KPVOCKP ] EJCTDWHQT=? ENTUET  VYQTGPKGPQYGIQRNKMWKCRKUFCP[EJPCF[UM QHUVTGCO1WV(KNG PQY[FCV  KH 1WV(KNG TGVWTP HQT KPVKKK 1WV(KNGUKP K GPFN 1WV(KNGENQUG  Rozdział 2. (cid:1) C++ w pigułce 17 QFE[VFCP[EJ KHUVTGCO+P(KNG PQY[FCV  YJKNG +P(KNGGQH ] +P(KNGIGVNKPG DWHQTUKGQH DWHQT  EQWVDWHQTGPFN _ +P(KNGENQUG  IGVEJ  TGVWTP _ Analizując powyższe zapisy łatwo zauważymy, iż zaraz po utworzeniu nowego pliku, przy pomocy instrukcji warunkowej KH sprawdzamy, czy czynność ta została wykonana pomyślnie. W przypadku niemożności stworzenia na dysku pliku o podanej nazwie, przy pomocy instrukcji TGVWTP wywołujemy wartość powrotną funkcji OCKP , co jest równoznaczne z opuszczeniem programu. W omawianym programie nie została użyta funkcja QRGP . Funkcji tej nie używa się zbyt często korzystając z klas strumieni, z tego względu, iż klasy HUVTGO, KHUVTGO oraz QHUVTGO posiadają odpowiednie konstruktory (inne funkcje składowe), które otwierają pliki automatycznie. Obsługa plików z wykorzystaniem klasy ios Jak zapewne pamiętasz, istnieją dwa podstawowe rodzaje plików, którymi w praktyce po- sługujemy się najczęściej. Są to pliki tekstowe oraz binarne. Pliki tekstowe, stanowiące zbiór znaków ASCII (lub Unicode), przechowują zawarte w nich informacje w kolejnych wierszach, z których każdy zakończony jest parą znaków 4.(. Pliki binarne zawierające kodowane dane różnią się od tekstowych tym, iż informacje w nich zawarte nie są prze- znaczone do bezpośredniego oglądania — są zrozumiałe jedynie dla określonych progra- mów. Bardzo wygodny dostęp do różnego rodzaju plików dają nam elementy klasy KQU. Wspomniano wcześniej, że jednym ze sposobów połączenia uprzednio utworzonego stru- mienia z plikiem jest wywołanie funkcji: XQKFQRGP EQPUVEJCT UKQUADCUGQRGPOQFGKQUADCUGQWV^ KQUADCUGKPNQPIRTQVGEVKQP  gdzie U oznacza nazwę pliku, która może zawierać pełną ścieżkę dostępu. Tryb otwarcia pliku określa parametr QRGPOQFG, który musi być przedstawiony w postaci jednej lub większej liczby określonych wartości, połączonych przy pomocy operatora binarnej sumy logicznej ^. W tabeli 2.1 zebrano dostępne wartości, jakie może przyjmaować parametr QRGPOQFG. Natomiast parametr RTQVGEVKQP opcjonalnie określa otwarcie zwykłego pliku. Jeżeli zechcemy, aby plik został otworzony np. w trybie do dopisywania, wystarczy po- służyć się bardzo prostą konstrukcją: QHUVTGCO1WV(KNG PQY[FCVKQUCRR  A dopisywania w trybie binarnym: QHUVTGCO1WV(KNG PQY[FCVKQUCRR^KQUDKPCT[  18 C++Builder 6. Ćwiczenia Tabela 2.1. Dopuszczalne tryby otwarcia pliku Wartości openmode Opis KQUCRR KQUCVG KQUKP KQUQWV KQUDKPCT[ KQUVTWPE Ćwiczenie 2.4. Otwarcie pliku w trybie do dopisywania (dołączenie wprowadzanych danych na końcu pliku). Ustawienie wskaźnika pliku na jego końcu. Otwarcie pliku w tzw. trybie wejściowym (w trybie do cwzytania). Wartość domyślna dla strumienia KHUVTGCO. Otwarcie pliku w tzw. trybie wyjściowym (w trybie do zwapisywania). Wartość domyślna dla strumienia QHUVTGCO. Otwarcie pliku binarnego. Po otwarciu zawartość pliku zostanie usunięta. Korzystając z tabeli 2.1 zmodyfikuj projekt Projekt_03.bpr (wydruk 2.3) w ten sposób, aby sprawdzić działanie pozostałych metod otwarcia apliku. Struktury w C++ Struktury, tworzące zbiór zmiennych złożonych z jednej lub z logicznie powiązanych kilku danych różnych typów, zgrupowanych pod jedną nazwą, są bardzo wygodnym typem danych, często definiowanym przez programistów C++. Na potrzeby obecnych ćwiczeń przedstawimy dwa bardzo często stosowane sposoby deklaracji oraz używania struktur. Słowo kluczowe UVTWEV (struktura) ułatwia logiczne pogrupowanie danych różnych typów. Po słowie UVTWEV w nawiasach klamrowych deklarujemy elementy składowe struktury wraz z ich typami bazowymi. Ćwiczenie 2.5. Zbudujemy naprawdę prostą bazę danych, w której przechowywać będziemy pewne in- formacje o wybranych studentach, tak jak pokazano toa na wydruku 2.4. Wydruk 2.4. Moduł Unit04.cpp projektu Projekt_04.bpr ilustrującegoW prosty przykład wykorzystania informacji zawartej w pewnej strukturze KPENWFGKQUVTGCOJ KPENWFGEQPKQJ KPENWFGUVFNKDJ RTCIOCJFTUVQR UVTWEV5VWFGPV] EJCT+OKG=? EJCT0CYKUMQ=? HNQCV ICOKP/CVGOCV[MC HNQCV ICOKP(K[MC HNQCV ICOKP+PHQTOCV[MC Rozdział 2. (cid:1) C++ w pigułce 19 EJCT,CMK5VWFGPV=? _ XQKF5VWFGPV+PHQ KPV5VWFGPV+PHQ   KPVOCKP ] 5VWFGPV CPG=? KPVKPFGZ EJCTDWHQT/=?DWHQT(=?DWHQT+=? ENTUET  FQ] EQWV+OKG EKPIGVNKPG CPG=KPFGZ?+OKGUKGQH CPG=KPFGZ?+OKG   EQWV0CYKUMQ EKPIGVNKPG CPG=KPFGZ?0CYKUMQ UKGQH CPG=KPFGZ?0CYKUMQ   EQWV ICOKP/CVGOCV[MC EKPIGVNKPG DWHQT/UKGQH DWHQT/    CPG=KPFGZ? ICOKP/CVGOCV[MCCVQH DWHQT/ CVQH EQWV ICOKP(K[MC EKPIGVNKPG DWHQT(UKGQH DWHQT(    CPG=KPFGZ? ICOKP(K[MCCVQH DWHQT(  EQWV ICOKP+PHQTOCV[MC EKPIGVNKPG DWHQT+UKGQH DWHQT+    CPG=KPFGZ? ICOKP+PHQTOCV[MCCVQH DWHQT+  EQWV1RKPKC EKPIGVNKPG CPG=KPFGZ?,CMK5VWFGPV UKGQH CPG=KPFGZ?,CMK5VWFGPV   EQWVGPFN KPFGZ  _YJKNG KPFGZ  HQT KPVKKK 5VWFGPV+PHQ K CPG=K?  IGVEJ  TGVWTP _  XQKF5VWFGPV+PHQ KPVPWOGT5VWFGPV+PHQ ] EQWV1UQDC TGMQTF PT PWOGT  GPFN EQWV+OKúK0CYKUMQ+PHQ+OKG EQWV+PHQ0CYKUMQGPFN EQWV ICOKP/CVGOCV[MC +PHQ ICOKP/CVGOCV[MCGPFN EQWV ICOKP(K[MC+PHQ ICOKP(K[MCGPFN EQWV ICOKP+PHQTOCV[MC +PHQ ICOKP+PHQTOCV[MCGPFN EQWV1RKPKC+PHQ,CMK5VWFGPVGPFN _ 20 C++Builder 6. Ćwiczenia W programie głównym w liniach 5. – 12. definiujemy strukturę 5VWFGPV, w której polach zapisywać będziemy interesujące nas informacje, czyli imię i nazwisko danej osoby, oceny z egzaminów z wybranych przedmiotów i na koniaec naszą opinię o studencie. Ponieważ chcemy mieć możliwość przechowywania w polach struktury informacji o więk- szej liczbie osób, dlatego w linii 16. deklarujemy tablicę CPG typu strukturalnego 5VWFGPV. Informacje przechowywane w polach struktury będą indeksowane, musimy zatem za- deklarować w linii 17. zmienną KPFGZ typu całkowitego. Oceny z poszczególnych egzaminów deklarowane są w strukturze 5VWFGPV jako prosty typ zmiennopozycyjny HNQCV. W trakcie działania programu oceny te wpisywać bę- dziemy z klawiatury w postaci ciągu znaków, które w dalszym etapie powinny zostać przekonwertowane na konkretne liczby. Z tego powodu łańcuchy znaków reprezentują- cych poszczególne oceny będą przechowywane w odpowiednich buforach deklarowa- nych w linii 18. programu. Proces wypełniania poszczególnych pól tablicy struktur CPG odbywa się w liniach 20. – 38. programu w pętli FQYJKNG. I tak, w pierwszej kolejności za pomocą funkcji składo- wej IGVNKPG strumienia wejściowego EKP wypełniamy pola +OKG oraz 0CYKUMQ tablicy struktur CPG (linie 22. – 24.). Elementy tablicy struktur (osoby) są indeksowane po- cząwszy od wartości . W linii 26. wczytujemy do bufora DWHQT/ ciąg znaków reprezentujących ocenę z wybra- nego przedmiotu. W linii 27. ciąg znaków znajdujący się w buforze zostanie zamienio- ny na liczbę typu zmiennopozycyjnego za pomocą zdefiniowanej w pliku nagłówko- wym stdlib.h funkcji CVQH . W tej samej linii programu liczba ta zostanie wpisana do pola ICOKP/CVGOCV[MC tablicy struktur CPG z odpowiednim indeksem określającym konkretną osobę. W podobny sposób wypełniamy pozostałe pola tablicy struktur CPG do momentu, kiedy zmienna KPFGZ nie przekroczy wartości określającej liczbę „zapamięta- nych” osób. W dalszym etapie rozwoju naszego programu zajdzie prawdopodobnie potrzeba po- nownego wyświetlenia (lub wyszukania i wyświetlenia) informacji o wybranych oso- bach (lub konkretnej osobie). Musimy zatem zaprojektować prostą funkcję rozwiązują- cą ten problem. W C++ istnieje konieczność deklarowania prototypów samodzielnie definiowanych funkcji. Prototyp naszej funkcji 5VWFGPV+PHQ typu XQKF (funkcja nie zwraca żadnej wartości) umieszczony jest w linii 13. programu. Funkcja posiada dwa parametry: pierwszy typu całkowitego KPV, określający numer osoby, drugi +PHQ typu strukturalnego 5VWFGPV, umożliwiający odwoływanie się do konkretnych pól struktury (informacji zawartych w strukturze). Zapis funkcji 5VWFGPV+PHQ znajduje się w liniach 44. – 53. naszego programu. Łatwo zauważymy, iż odpowiednie dane pobierane są z określonych pól struktury poprzez strumień wyjściowy EQWV. Proces wyświetlania danych na ekranie odbywa się w liniach 39. – 40., gdzie zmienna ste- rująca K w pętli HQT przebiega już tylko indeksy tablicy struktur CPG. Na rysunku 2.3 pokazano omawiany program w trakcie dziaałania. Rozdział 2. (cid:1) C++ w pigułce 21 Rysunek 2.3. Projekt Projekt_04.bpr po uruchomieniu Samodzielne tworzenie plików nagłówkowych Wspominaliśmy wcześniej, iż w C++ bardzo wiele funkcji bibliotecznych korzysta z wła- snych struktur oraz typów danych, których definicje znajdują się w plikach nagłówkowych. Korzystając z faktu, iż stworzyliśmy przed chwilą własny strukturalny typ danych, zmo- dyfikujemy Projekt_04.bpr w ten sposób, aby posługiwał się plikiem nagłówkowym zawie- rającym definicję struktury 5VWFGPV. Ćwiczenie 2.6. 1. Poleceniem menu FileNewOtherHeader File uaktywniamy okno edycji ułatwiające tworzenie i zapisywanie na dysku własnych, nowo twoarzonych plików nagłówkowych. 2. Kod pliku zaczyna się od dyrektywy kompilacji warunkoawej KHPFGH (ang. if not defined — jeśli nie zdefiniowano). Za dyrektywą następuje pisaana dużymi literami nazwa makra z reguły rozpoczynająca się od znaku poadkreślenia. 3. Następnie, przy pomocy dyrektywy FGHKPG definiujemy nazwę makra w ten sposób, aby zaczynała się od znaku podkreślenia. Nazwa makra paowinna odpowiadać nazwie, którą później nadamy plikowi nagłówkowemu. 4. Po zdefiniowaniu makra, należy zdefiniować własny typ astrukturalny. 5. Definicja makra kończy się dyrektywą kompilacji warunkaowej GPFKH. KHPFGHA567 06A*CNGPKGKHFGH FGHKPGA567 06* UVTWEV5VWFGPV] EJCT+OKG=? EJCT0CYKUMQ=? HNQCV ICOKP/CVGOCV[MC HNQCV ICOKP(K[MC HNQCV ICOKP+PHQTOCV[MC EJCT,CMK5VWFGPV=? _ GPFKH 22 C++Builder 6. Ćwiczenia 6. Tak określony plik nagłówkowy zapiszemy w aktualnym kaatalogu pod nazwą UVWFGPVJ. Bardzo często (nawet przez nieuwagę) osoby rozpoczynawjące naukę C++ popełniają pewien błąd. Mianowicie zamiast dyrektywy KHPFGH używają bardzo podobnej w zapisie KHFGH (ang. if defined — jeśli zdefiniowano). Różnica pomiędzy tymi dyrektywawmi jest dosyć wyraźna. Jeżeli za pomocą dyrektywy FGHKPG została wcześniej zdefiniowana pewna makrodefinicja,w wówczas sekwencja instrukcji występująca pomiędzy dywrektywami KHFGH oraz GPFKH będzie zawsze kompilowana. Sekwencja instrukcji występująca pomiędzy dyrektywamwi KHPFGH oraz GPFKH będzie kompilowana jedynie wówczas, gdy dana makrodefinicjaw nie została wcześniej zdefiniowana. 7. Tak przygotowany plik nagłówkowy zawierający definicaję struktury 5VWFGPV bez problemu wykorzystamy w naszym programie. W tym celu waystarczy dołączyć go do kodu zaraz po dyrektywie RTCIOCJFTUVQR:  RTCIOCJFTUVQR KPENWFGUVWFGPVJ XQKF5VWFGPV+PHQ KPV5VWFGPV+PHQ   Zmodyfikowany Projekt_04.bpr możemy już samodzielnie przetestować. Klasy w C++ Klasa jest jednym z podstawowych pojęć obiektowego języka C++. Przy pomocy słowa kluczowego ENCUU definiujemy nowy typ danych, będący w istocie połączeniem danych i instrukcji, które wykonują na nich działania. Umożliwia on tworzenie nowych (lub wyko- rzystanie istniejących) obiektów będących reprezentantami klasy. Konstrukcja klasy umożli- wia deklarowanie elementów prywatnych (ang. private), publicznych (ang. public) oraz chronionych (ang. protected). Domyślnie, w standardowym języku C++ wszystkie ele- menty klasy traktowane są jako prywatne, co oznacza, że dostęp do nich jest ściśle kontro- lowany i żadna funkcja nie należąca do klasy nie może z nich korzystać. Jeżeli w definicji klasy pojawią się elementy publiczne, oznacza to, że mogą one uzyskiwać dostęp do innych części programu. Chronione elementy klasy dostępne są jedynie w danej klasie lub w kla- sach potomnych. Ogólną postać definicji klasy można przedstawić w sposób następujący: ENCUU0CYC-NCU[ ] RTKXCVG RT[YCVPGFCPGKHWPMELG RWDNKE RWDNKEPGFCPGKHWPMELG RTQVGEVGF EJTQPKQPGFCPGKHWPMELG _ IGORNCTG-NCU[NKUVCGIGORNCT[MNCU[ Rozdział 2. (cid:1) C++ w pigułce 23 Definicja klasy jest zawsze źródłem definicji jej obiektów. Jeszcze kilkanaście lat temu przed pojawieniem się wizualnych środowisk programistycznych słowo obiekt (ang. object) było jednoznacznie utożsamiane z klasą2. Obecnie sytuacja nieco się skompliko- wała, gdyż słowo obiekt otrzymało o wiele szersze znaczenie. Z tego względu wygodniej jest posługiwać się szeroko stosowanym w anglojęzycznej literaturze sformułowaniem egzemplarz klasy (ang. class instance). Otóż, po zdefiniowaniu klasy tworzymy obiekt jej typu o nazwie takiej samej, jak nazwa klasy występująca po słowie ENCUU. Jednak klasy tworzymy po to, by stały się specyfikatorami typów danych. Jeżeli w instrukcji definicji klasy po zamykającym nawiasie klamrowym podamy pewną nazwę, utworzymy tym samym określony egzemplarz klasy, który od tej chwili traktowany jest jako nowy, pełnoprawny typ danych. Oczywiście jedna klasa może być źródłem definicji wielu jej egzemplarzy. Innym sposobem utworzenia egzemplarza danej klasy będzie nasatępująca konstrukcja:  ENCUU0CYC-NCU[ ] RTKXCVG RT[YCVPGFCPGKHWPMELG RWDNKE RWDNKEPGFCPGKHWPMELG RTQVGEVGF EJTQPKQPGFCPGKHWPMELG _  KPVOCKP  IGORNCT-NCU[0CYC-NCU[  Ćwiczenie 2.7. Jako przykład stworzymy bardzo prostą w swojej budowie klasę 5VWFGPV, przy pomocy której będziemy mogli odczytać wybrane informacje o peawnej osobie. 1. Deklaracja klasy 5VWFGPV składającej się z części publicznej i prywatnej możea wyglądać następująco: ENCUU5VWFGPV ] RWDNKE XQKF,CMK5VWFGPV EJCT  XQKF+PKELCNKCELC  XQKF(KPCNKCELC  RTKXCVG EJCT 0CYKUMQ _ W sekcji publicznej (rozpoczynającej się od słowa klucazowego RWDNKE) deklaracji klasy 5VWFGPV umieściliśmy prototypy trzech funkcji składowych klaasy. W sekcji prywatnej (rozpoczynającej się od słowa kluczowego RTKXCVG) umieściliśmy deklarację 2 Jako ciekawostkę podajmy, iż w latach 70. XX wieku słowow obiekt utożsamiano z pewnym wydzielonym obszarem pamięci w dużych maszynach cyfrowych oraz innych maszynach zwanych mini- i mikrokomputerami. W takim znaczeniu słowa obiekt używali Brian Kernighan i Dennis Ritchie — twórcy jęzwyka C. 24 C++Builder 6. Ćwiczenia jednej zmiennej (dokładniej — wskaźnika) składowej klaasy. Mimo że istnieje możliwość deklarowania zmiennych publicznych w klasie, ato jednak zalecane jest, aby ich deklaracje były umieszczane w sekcji prywatneaj, zaś dostęp do nich był możliwy poprzez funkcje z sekcji publicznej. Jak już się azapewne domyślasz, dostęp do wskaźnika 0CYKUMQ z sekcji prywatnej będzie możliwy właśnie poprzez funakcję ,CMK5VWFGPV , której jedynym parametrem jest wskaźnik. Tego typua technika programowania nosi nazwę enkapsulacji danych, co oznacza, że dostęp do prywatnych danych jest zawsze ściśle kontrolowany. 2. Jak się zapewne domyślasz, rolą bezparametrowej funkcjai +PKELCNKCELC będzie zainicjowanie danych. Ponieważ omawiana funkcja jest cazęścią klasy 5VWFGPV, to przy jej zapisie w programie musimy poinformować kompilataor, iż właśnie do niej należy. Operator rozróżniania zakresu  (ang. scope resolution operator) służy temu celowi. XQKF5VWFGPV+PKELCNKCELC ] 0CYKUMQPGYEJCT=? EQWV2T[FKGNQPQRCOKúè  EQWVGPFN0CEKħPKL PVGTGPFN IGVEJCT  TGVWTP _ Jedyną rolą funkcji +PKELCNKCELC jest dynamiczne przydzielenie pamięci do wskaźnika 0CYKUMQ przy pomocy operatora PGY. Tekst wyświetlany jest jedynie w celach poglądowych. 3. Funkcja (KPCNKCELC zajmuje się zwolnieniem przy pomocy operatora FGNGVG uprzednio przydzielonej pamięci. XQKF5VWFGPV(KPCNKCELC ] FGNGVG=?0CYKUMQ EQWV YQNPKQPQRCOKúè EQWVGPFN0CEKħPKL PVGTGPFN TGVWTP _ 4. W funkcji ,CMK5VWFGPV dokonujemy porównania dwóch ciągów znaków. Przy pomocy funkcji UVTEOR z modułu UVTKPIJ porównujemy dwa łańcuchy znaków, czyli łańcuch wskazywany przez 0CYKUMQ oraz drugi, odpowiadający już konkretnemu nazwisku danej osoby. Jeżeli oba łańcuchy są identyczne,a funkcja UVTEOR zwraca wartość , zaś następnie przy pomocy strumienia wyjściowego aEQWV wyświetlany jest odpowiedni komunikat. XQKF5VWFGPV,CMK5VWFGPV EJCT U ] 0CYKUMQU KH UVTEOR 0CYKUMQ9CEMQYUMK  UVTER[ 0CYKUMQDCTFQFQDT[UVWFGPV  KH UVTEOR 0CYKUMQ,CPMQYUMK  UVTER[ 0CYKUMQMKGRUMKUVWFGPV  EQWV0CYKUMQGPFNGPFN TGVWTP _ Rozdział 2. (cid:1) C++ w pigułce 25 5. W głównej funkcji OCKP wywołamy opisane wcześniej elementy klasy 5VWFGPV. KPVOCKP ] EJCT -VQT[5VWFGPV -VQT[5VWFGPVPGYEJCT=? 5VWFGPV+PHQ5VWFGPV ENTUET  EQWV2QFCLPCYKUMQ IGVU -VQT[5VWFGPV  +PHQ5VWFGPV+PKELCNKCELC  +PHQ5VWFGPV,CMK5VWFGPV -VQT[5VWFGPV  +PHQ5VWFGPV(KPCNKCELC  IGVEJ  FGNGVG=?-VQT[5VWFGPV TGVWTP _ I tak, w linii 3. deklarujemy wskaźnik -VQT[5VWFGPV przechowujący wpisywane z klawiatury nazwisko (dokładniej — wskazujący na piearwszą literę nazwiska), zaś w linii 4. przydzielamy mu przy pomocy operatora PGY odpowiedni obszar pamięci. W linii 5. deklarujemy egzemplarz +PHQ5VWFGPV klasy 5VWFGPV. W liniach 6. – 8. wczytujemy nazwisko studenta. Ponieważ używamy wskaźniaka, wygodniej jest w tym celu wykorzystać funkcję IGVU , której prototyp znajduje się w pliku stdio.h. W liniach 10. i 11. w odpowiedniej kolejności wywołujemy afunkcje składowe egzemplarza +PHQ5VWFGPV klasy 5VWFGPV. Aby wywołać funkcję składową egzemplarza klasy z fragmentu programu nie należącego do klasy (w naaszym przypadku z głównej funkcji OCKP ), należy w kolejności podać: nazwę egzemplarza klasy, oaperator w postaci kropki, zaś po nim nazwę właściwej funkcjai. W linii 13. zwalniamy pamięć przydzieloną wskaźnikowi -VQT[5VWFGPV. Kompletny kod modułu Unit05.cpp projektu Projekt_05.bpr korzystającego z omawianej klasy przedstawiono na wydruku 2.5, zaś na rysunku 2.4 pokazano efekt naszej pracy. Wydruk 2.5. Kod modułu Unit05.cpp KPENWFGKQUVTGCOJ KPENWFGUVTKPIJ KPENWFGEQPKQJ KPENWFGUVFKQJ RTCIOCJFTUVQR ENCUU5VWFGPV ] RTKXCVG EJCT 0CYKUMQ RWDNKE XQKF,CMK5VWFGPV EJCT  XQKF+PKELCNKCELC  XQKF(KPCNKCELC  _+PHQ5VWFGPV  XQKF5VWFGPV+PKELCNKCELC ] 0CYKUMQPGYEJCT=? EQWV2T[FKGNQPQRCOKúè EQWVGPFN0CEKħPKL PVGTGPFN 26 C++Builder 6. Ćwiczenia IGVEJCT  TGVWTP _  XQKF5VWFGPV(KPCNKCELC ] FGNGVG=?0CYKUMQ EQWV YQNPKQPQRCOKúè EQWVGPFN0CEKħPKL PVGTGPFN TGVWTP _  XQKF5VWFGPV,CMK5VWFGPV EJCT U ] 0CYKUMQU KH UVTEOR 0CYKUMQ9CEMQYUMK  UVTER[ 0CYKUMQDCTFQFQDT[UVWFGPV  KH UVTEOR 0CYKUMQ,CPMQYUMK  UVTER[ 0CYKUMQMKGRUMKUVWFGPV  EQWV0CYKUMQGPFNGPFN TGVWTP _  KPVOCKP ] EJCT -VQT[5VWFGPV -VQT[5VWFGPVPGYEJCT=? 5VWFGPV+PHQ5VWFGPV ENTUET  EQWV2QFCLPCYKUMQ IGVU -VQT[5VWFGPV  +PHQ5VWFGPV+PKELCNKCELC  +PHQ5VWFGPV,CMK5VWFGPV -VQT[5VWFGPV  +PHQ5VWFGPV(KPCNKCELC  IGVEJ  FGNGVG=?-VQT[5VWFGPV TGVWTP _ Rysunek 2.4. Projekt Projekt_05.bpr w trakcie działania Rozdział 2. (cid:1) C++ w pigułce 27 Konstruktor i destruktor Przedstawiony na przykładzie projektu Projekt_05.bpr sposób inicjowania i finalizowania działania różnych obiektów (w tym egzemplarzy klas) jest obecnie rzadko wykorzystywany w praktyce (poza zupełnie szczególnymi przypadkami, w których mamy jakieś konkretne wymagania odnośnie działania programu). Ponieważ konieczność inicjalizowania (i ew. finalizowania) np. egzemplarzy klas w C++ występuje bardzo często, dlatego w praktyce wykorzystujemy automatyczną ich inicjalizację (i ew. finalizację). Tego rodzaju automaty- zacja możliwa jest dzięki wykorzystaniu specjalnych funkcji składowych klasy zwanych konstruktorami. Konstruktor i destruktor zawsze posiadają taką samą nazwę jak klasa, do której należą. Różnica w ich zapisie polega na tym, że nazwa destruktora poprzedzona jest znakiem `. Ćwiczenie 2.8. Zmodyfikujemy poprzedni program w taki sposób, aby klasa 5VWFGPV posiadała swój kon- struktor i destruktor. 1. Po wprowadzeniu konstruktora i destruktora do klasy a5VWFGPV, jej definicja przybierze następującą postać: ENCUU5VWFGPV ] RWDNKE XQKF,CMK5VWFGPV EJCT  5VWFGPV MQPUVTWMVQT `5VWFGPV FGUVTWMVQT RTKXCVG EJCT 0CYKUMQ _ Natychmiast zauważymy, iż w C++ nie określa się typów paowrotnych konstruktorów i destruktorów, gdyż z założenia nie mogą zwracać żadanych wartości. 2. Zrozumienie idei używania konstruktorów i destruktoraów ułatwi nam prześledzenie poniższego wydruku. Wydruk 2.6. Kod modułu Unit06.cpp projektu Projekt_06.bpr wykorzysWtującego funkcje składowe w postaci konstruktora i destruktora klasy KPENWFGKQUVTGCOJ KPENWFGUVTKPIJ KPENWFGEQPKQJ KPENWFGUVFKQJ RTCIOCJFTUVQR ENCUU5VWFGPV ] RWDNKE XQKF,CMK5VWFGPV EJCT  5VWFGPV MQPUVTWMVQT `5VWFGPV FGUVTWMVQT RTKXCVG EJCT 0CYKUMQ _ 28 C++Builder 6. Ćwiczenia MQPUVTWMVQTMNCU[5VWFGPV 5VWFGPV5VWFGPV ] 0CYKUMQPGYEJCT=? EQWV-QPUVTWMVQTMNCU[QUVCđCKPKELQYCP[ EQWVGPFN0CEKħPKL PVGTGPFN IGVEJCT  _  XQKF5VWFGPV,CMK5VWFGPV EJCT U ] 0CYKUMQU KH UVTEOR 0CYKUMQ9CEMQYUMK  UVTER[ 0CYKUMQDCTFQFQDT[UVWFGPV  KH UVTEOR 0CYKUMQ,CPMQYUMK  UVTER[ 0CYKUMQMKGRUMKUVWFGPV  EQWV0CYKUMQGPFN EQWVGPFN0CEKħPKLMNCYKUGPFN TGVWTP _ FGUVTWMVQTMNCU[5VWFGPV 5VWFGPV`5VWFGPV ] FGNGVG=?0CYKUMQ EQWV-QPUVTWMVQTQUVCđPKUEQP[ 2QYVÎTPKGPCEKħPKLMNCYKUGPFN IGVEJ  _  KPVOCKP ] EJCT -VQT[5VWFGPV -VQT[5VWFGPVPGYEJCT=? 5VWFGPV+PHQ5VWFGPV ENTUET  EQWV2QFCLPCYKUMQ IGVU -VQT[5VWFGPV  +PHQ5VWFGPV,CMK5VWFGPV -VQT[5VWFGPV  IGVEJ  FGNGVG=?-VQT[5VWFGPV TGVWTP _ Uruchamiając program bez trudu przekonamy się, iż konstruktor 5VWFGPV jest automa- tycznie uruchamiany podczas tworzenia egzemplarza klasy, czyli w momencie wykonywania instrukcji deklarującej egzemplarz klasy. Jest to jedna z cech odróżniających język C++ od zwykłego C. W C++ deklaracje zmiennych wykonywane są wa trakcie działania programu. Ze względu na to, że każdy egzemplarz klasy jest tworzony w trakcie wykonywania in- strukcji jego deklaracji, musi on być niszczony automatycznie w trakcie opuszczania bloku programu, w którym powyższa deklaracja się znajduje. Testując projekt Projekt_06.bpr bez trudu przekonamy się, iż mimo że destruktor `5VWFGPV nie został jawnie wywołany, to jednak kod jego zostanie wykonany, zwalniając tym samym pamięć przydzieloną uprzed- nio wskaźnikowi 0CYKUMQ przez konstruktor 5VWFGPV . Rozdział 2. (cid:1) C++ w pigułce 29 Ćwiczenie 2.9. Samodzielnie przetestuj projekty Projekt_05.bpr oraz Projekt_06.bpr pod kątem okre- ślenia różnic w działaniu zwykłych funkcji składowych +PKELCNKCELC i (KPCNKCELC oraz konstruktora 5VWFGPV i destruktora `5VWFGPV . Ćwiczenie 2.10. Często, w celu uczynienia programu bardziej przejrzystym, definicje klas umieszczamy w oddzielnym pliku nagłówkowym. Postaraj się samodzielanie stworzyć taki plik i włączyć go do programu. Inne spojrzenie na klasy. Własności C++Builder, jako kompletne środowisko programowania, wprowadza bardziej ogólne pojęcie klasy. Otóż w Builderze definicję klasy można znaacznie wzbogacić, tzn. w skład tej definicji oprócz sekcji prywatnej i publicznej może wchodzić również sekcja publi- kowana (ang. published) rozpoczynająca się od słowa kluczowego AARWDNKUJGF. W tej sekcji umieszcza się z reguły deklaracje funkcji, czyli deklaracje metod związane z kom- ponentami pochodzącymi z biblioteki VCL. Dodatkowo klasa może zawierać też definicje własności rozpoczynające się od słowa AARTQRGTV[. Warto w tym miejscu zauważyć, iż definicje w klasie związane z biblioteką VCL będą rozpoczynać się od pewnych słów kluczowych, poprzedzonych podwójnym znakiem podkreślenia. Chociaż do klas związanych z biblioteką komponentów wizualnych powrócimy jeszcze w dalszej części książki, to jednak w tym miejscu pokażemy, w jaki sposób można zbudować parostą własność w klasie. Ćwiczenie 2.11. Zbudujemy prostą klasę, której wykorzystanie w programie umożliwi w sposób bardzo elegancki i przejrzysty odczytywanie i zapisywanie danych w postaci nazwisk wybranych osób. W tym celu skorzystamy z definicji własności. Ponieważ ogólnie przyjętą konwencją jest to, aby w tego typu programach posługiwać się pewnymi standardowymi przedrostkami dla zmiennych oraz funkcji, w dalszej części opisu będziemy wykorzystywać nazewnictwo angielskie — po to, by nie tworzyć mieszanki nazw polsakich i angielskich (np. 5GV0CYKUMQ). 1. Na potrzeby naszego ćwiczenia samodzielnie zbudujemy wałasność, przy pomocy której będziemy w stanie odczytywać i przypisywać oadpowiednie wartości (w tym przypadku łańcuchy znaków reprezentujące nazwiska ia imiona osób). Każda własność służy do przechowywania wartości, zatem należy zadeklaarować związaną z nią zmienną (tzw. pole w klasie). Ogólnie przyjętą konwencją jest to,a że zmienne mają takie same nazwy, jak związane z nimi własności, ale poprzedzoane są literą (. W naszym programie w sekcji prywatnej definicji klasy 5VWFGPVU zadeklarujemy jedną taką zmienną typu #PUK5VTKPI, reprezentującą tablicę indeksującą nazwiska studenatów. Dodatkowo w tej samej sekcji zadeklarujemy dwie funkcaje (metody): )GV0COG , która w przyszłości będzie odczytywała przy pomocy aindeksu imię i nazwisko wybranej osoby oraz 5GV0COG , za pomocą której będzie można przypisać odpowiedni łańcuch znaków (imię i nazwisko) do odpowiedniego indeksu w atablicy. 30 C++Builder 6. Ćwiczenia RTKXCVG #PUK5VTKPI(0COG=? #PUK5VTKPI)GV0COG KPVKPFGZ  XQKF5GV0COG KPV#PUK5VTKPI  2. Przechodzimy teraz do deklaracji samej własności. W tyam celu należy użyć słowa kluczowego AARTQRGTV[. Dla naszych potrzeb wystarczy, by własność służyła wyłącznie do przekazywania danych (imion i nazwisk aosób) przy pomocy indeksu. Własność zadeklarujemy w sekcji publicznej definicji kalasy. Zdefiniowana przez nas własność 0COG będzie odczytywać aktualny stan tablicy (0COG przy pomocy dyrektywy TGCF, a następnie przekazywać (zapisywać) ją do funkcji 5GV0COG korzystając z dyrektywy YTKVG. RWDNKE 5VWFGPVU ]_MQPUVTWMVQT `5VWFGPVU ]_FGUVTWMVQT AARTQRGTV[#PUK5VTKPI0COG=KPVKPFGZ? ]TGCF)GV0COGYTKVG5GV0COG_ 3. Jednoparametrowa funkcja (metoda) )GV0COG ma bardzo prostą budowę i służyć będzie do odpowiedniego indeksowania nazwisk: #PUK5VTKPI5VWFGPVU)GV0COG KPVK ] TGVWTP(0COG=K? _ 4. Dwuparametrowa funkcja (metoda) 5GV0COG również nie jest skomplikowana i przypisuje odpowiedniemu indeksowi tablicy ciąg znaaków określony przez PCOGU. XQKF5VWFGPVU5GV0COG KPVKEQPUV#PUK5VTKPIPCOGU ] (0COG=K?PCOGU _ Kompletny kod modułu Unit_07.cpp projektu Projekt_07.bpr wykorzystującego własność w klasie pokazany jest na wydruku 2.7. Wydruk 2.7. Moduł Unit07.cpp KPENWFGXENJ KPENWFGUVFKQJ KPENWFGEQPKQJ RTCIOCJFTUVQR ENCUU5VWFGPVU ] RWDNKE 5VWFGPVU ]_MQPUVTWMVQTMNCU[ `5VWFGPVU ]_FGUVTWMVQTMNCU[ AARTQRGTV[#PUK5VTKPI0COG=KPVKPFGZ? ]TGCF)GV0COGYTKVG5GV0COG_ RTKXCVG #PUK5VTKPI(0COG=? #PUK5VTKPI)GV0COG KPVKPFGZ  XQKF5GV0COG KPV#PUK5VTKPI  _2GTUQPGIGORNCT2GTUQP QUQDC MNCU[5VWFGPVU  Rozdział 2. (cid:1) C++ w pigułce 31 #PUK5VTKPI5VWFGPVU)GV0COG KPVK ] TGVWTP(0COG=K? _  XQKF5VWFGPVU5GV0COG KPVKEQPUV#PUK5VTKPIPCOGU ] (0COG=K?PCOGU _  KPVOCKP ] ENTUET  2GTUQP0COG=?9CEGM,CPMQYUMKY[YQđWLG2GTUQP5GV0COG 2GTUQP0COG=?,CPGM9CEMQYUMK 2GTUQP0COG=?,QNC.QDWKPUMC HQT KPVKKK RWVU 2GTUQP0COG=K?EAUVT Y[YQđWLG2GTUQP)GV0COG  IGVEJ  TGVWTP _ W głównej funkcji programu, w celu wyświetlenia odpowiednich łańcuchów znaków, użyliśmy metody EAUVT zwracającej wskaźnik (EJCT ) do pierwszego znaku łańcucha identyfikującego własność tablicową 0COG egzemplarza 2GTUQP klasy 5VWFGPVU. Można też zauważyć, iż użycie w programie słowa AARTQRGTV[ oraz typu #PUK5VTKPI (elementy te nie są zdefiniowane w standardowym C++) wymaga włączenia do kodu modułu pliku nagłówkowego vcl.h (patrz rysunek 2.1). Funkcje przeładowywane Stosowanie w programie funkcji przeładowywanych (często też nazywanych funkcjami przeciążanymi) w bardzo wielu wypadkach może znacznie ułatwić pisanie rozbudowa- nych programów. Używanie funkcji przeładowywanych nierozerwalnie wiąże się z tzw. polimorfizmem w C++. Polega on na zdefiniowaniu większej liczby funkcji posiadających taką samą nazwę, ale o różnych postaciach listy parametrów. Możliwość przeciążania funkcji jest w C++ czymś bardzo naturalnym i nie wymaga stosowania w ich deklaracjach specjalnych dyrektyw. Dla porównania przypomnijmy, że w Delphi funkcje czy procedury przeciążane zawsze należy deklarować z dyrektywą QXGTNQCF. Pod względem używania funkcji przeładowywanych C++ nie generuje żadnego nadmiarowego kodu w porównaniu z Object Pascalem. Ćwiczenie 2.12. Stworzymy program obliczający kolejne całkowite potęgia liczb różnych typów. 1. Program zawierać będzie dwie podobne (ale nie takie saame) funkcje o nazwie RQYGT (potęga), zwracające kolejne potęgi pobranego argumenatu. Prototypy tych funkcji możemy zapisać w sposób następujący: 32 C++Builder 6. Ćwiczenia WPUKIPGFKPVRQYGT WPUKIPGFKPVZWPUKIPGFKPV[  FQWDNGRQYGT FQWDNGFZWPUKIPGFNQPIF[  2. Następnie zapiszmy ciała tych funkcji: WPUKIPGFKPVRQYGT WPUKIPGFKPVZWPUKIPGFKPV[ ] WPUKIPGFKPVK HQT KK[K  Z TGVWTP _  FQWDNGRQYGT FQWDNGFZWPUKIPGFNQPIF[ ] FQWDNG HQT WPUKIPGFKPVKKF[K  FZ TGVWTP _ Jak widać, nazwa RQYGT nie oznacza żadnej konkretnej funkcji, a jedynie ogaólny rodzaj działania wykonywanego na konkretnym typie laiczb. 3. Wybór wersji funkcji odpowiadającej określonym potrzebaom programisty jest wykonywany automatyczne przez kompilator, dzięki poadaniu typu parametrów aktualnych wywoływanej funkcji RQYGT . Czynność tę wykonujemy wywołując odpowiednie funkcje w programie głównym. KPVOCKP ] ENTUET  HQT WPUKIPGFKPVKKK EQWVGPFN@KRQYGT K  EQWVGPFN HQT WPUKIPGFKPVKKK EQWVGPFN@KRQYGT K   EQWVGPFN0CEKħPKLMNCYKU IGVEJ  TGVWTP _ Jak łatwo zauważyć, główną zaletą przeładowywania funkacji jest to, że bez problemu można wywoływać powiązane ze sobą zestawy instrukcjia za pomocą tej samej nazwy, co pozwala, tak jak w pokazanym przypadku, zredukowaać dwie nazwy do jednej. Kompletny kod źródłowy głównego modułu projektu Projekt_08.bpr, wykorzystującego przeładowywane funkcje, zamieszczoano na wydruku 2.8. Wydruk 2.8. Moduł Unit08.cpp KPENWFGKQUVTGCOJ KPENWFGEQPKQJ RTCIOCJFTUVQR RTQVQV[R[RTGđCFQY[YCPGLHWPMELKRQYGT WPUKIPGFKPVRQYGT WPUKIPGFKPVZWPUKIPGFKPV[  FQWDNGRQYGT FQWDNGFZWPUKIPGFNQPIF[  Rozdział 2. (cid:1) C++ w pigułce 33 KPVOCKP ] ENTUET  HQT WPUKIPGFKPVKKK EQWVGPFN@KRQYGT K  EQWVGPFN HQT WPUKIPGFKPVKKK EQWVGPFN@KRQYGT K   EQWVGPFN0CEKħPKLMNCYKU IGVEJ  TGVWTP _  WPUKIPGFKPVRQYGT WPUKIPGFKPVZWPUKIPGFKPV[ ] WPUKIPGFKPVK HQT KK[K  Z TGVWTP _  FQWDNGRQYGT FQWDNGFZWPUKIPGFNQPIF[ ] FQWDNG HQT WPUKIPGFKPVKKF[K  FZ TGVWTP _ Kończąc rozważania o funkcjach przeładowywanych należy zauważyć, iż teoretycznie możemy nadawać identyczne nazwy funkcjom wykonującym różne działania, np. mno- żenie, potęgowanie i logarytmowanie. Jednak z praktycznego punktu widzenia nie po- winniśmy postępować w ten sposób. Zawsze należy dążyć do tego, aby przeładowywać funkcje wykonujące te same operacje. Ćwiczenie 2.13. Postaraj się zmodyfikować Projekt_08.bpr w taki sposób, aby bazował na pewnej klasie wykorzystującej omawiane funkcje. Niejednoznaczność Polimorfizm, którego przykładem jest możliwość przeładowywania funkcji, stanowi jedną z wielkich zalet obiektowego języka C++, jednak również niesie ze sobą (szczególnie dla mniej doświadczonych programistów) pewne pułapki. Jedną z nich jest niejedno- znaczność. Głównym źródłem niejednoznaczności w C++ są automatyczne konwersje typów. Uważny Czytelnik na pewno spostrzegł, w jaki sposób w programie przedstawionym na wydruku 2.8 wywoływane są funkcje należące do swoich prototypów: 34 C++Builder 6. Ćwiczenia WPUKIPGFKPVRQYGT WPUKIPGFKPVZWPUKIPGFKPV[ RTQVQV[R HQT WPUKIPGFKPVKKK EQWVGPFN@KRQYGT K  Y[YQđCPKGYRTQITCOKG oraz: FQWDNGRQYGT FQWDNGFZWPUKIPGFNQPIF[ RTQVQV[R HQT WPUKIPGFKPVKKK EQWVGPFN@KRQYGT K   Y[YQđCPKGYRTQITCOKG Funkcja RQYGT została przeładowana w taki sposób, że może pobierać argumenty w postaci par liczb typu WPUKIPGFKPV, WPUKIPGFKPV oraz FQWDNG, WPUKIPGFNQPI. Pierwsza instruk- cja wywołania funkcji RQYGT będzie jednoznaczna, gdyż nie musi występować żadna konwersja danych pomiędzy jej parametrami formalnymi i aktualnymi. Rozpatrzmy przy- padek, gdy funkcja RQYGT wywoływana jest z parametrem typu całkowitego WPUKIPGF KPV, będącego typem zmiennej sterującej K w pętli HQT , zaś jednym z jej parametrów formalnych (zdeklarowanym w jej prototypie) jest zmienna typu WPUKIPGFNQPI. W takiej sytuacji kompilator „nie wie”, czy zmienną taką przekształcić na typ NQPIKPV, czy NQPI FQWDNG. Jeżeli wywołalibyśmy funkcję w programie w sposób następujący: HQT WPUKIPGFKPVKKK EQWVGPFN@KRQYGT K  DđúFPGY[YQđCPKGYRTQITCOKG możemy spodziewać się wystąpienia przykrego komunikaatu kompilatora: =  TTQT?7PKVERR   #ODKIWKV[DGVYGGP RQYGT WPUKIPGFKPVWPUKIPGFKPV CPF RQYGT FQWDNGWPUKIPGFNQPI Aby uniknąć tego typu dwuznaczności, często uciekamy się do pewnego fortelu. Mianowicie wystarczy do liczby deklarowanej jako całkowita dodać wartość , aby kompilator do- konał jej automatycznej konwersji na typ zmiennopozaycyjny. Funkcje ogólne Funkcjami ogólnymi posługujemy się w sytuacjach, w których wymagamy, aby definicja danej funkcji zawierała całość operacji wykonywanych na danych różnych typów. Funkcję ogólną tworzymy przy pomocy słowa kluczowego VGORNCVG (szablon). Jego intuicyjne znaczenie jest bardzo trafne — szablon służy do ogólnegoa opisu działań wykonywanych przez daną funkcję, zaś dalszymi szczegółami powinien zająć się już sam kompilator C++. Szkielet definicji funkcji ogólnej rozpoczyna się właaśnie od słowa VGORNCVG: VGORNCVGENCUU6[R CP[EJ 6[R YTCECP[0CYC(WPMELK NKUVCRCTCOGVTÎY ] KPUVTWMELG _ Rozdział 2. (cid:1) C++ w pigułce 35 Ćwiczenie 2.14. Jak zapewne wiesz, jedną z właściwości języków C i C++ jest to, iż wszystkie argumenty funkcji przekazywane są przez wartość. Wynika z tego, że wywoływana funkcja otrzymuje wartości swoich argumentów, a nie ich adresy. Można oczywiście spowodować, aby funkcja zmieniała wartości zmiennych w funkcji wywołującej. W tym celu funkcja wywołująca musi przekazać adresy swoich zmiennych. Zbudujemy prostą funkcję ogólną, która zmieniać będzie wartości dwóch zmiennych przekazywanych jej w instrukcji wywołania. Funkcja będzie porównywać dwie zmienne i jako wartość powroatną zwracać większą z liczb. 1. Zadeklarujemy prostą funkcję ogólną o nazwie OCZ . VGORNCVGENCUU6 6OCZ 6Z6[ ] TGVWTP Z [ !Z[ _ Litera 6 oznacza tutaj nazwę zastępczą typu danych wykorzystaywanych przez dwuparametrową funkcją OCZ . Zaletą podawania nazwy zastępczej jest to, że kompilator zawsze automatycznie zastąpi ją rzeczyawistym typem danych w trakcie tworzenia konkretnej wersji funkcji. W funkcaji tej wykorzystaliśmy operator warunkowy ! (pytajnik i dwukropek). Znaczenie jego jest następująace: !   Jeżeli wartość logiczna wyrażenia (lub warunku)  występującego po lewej stronie znaku ! jest prawdą (wartość różna od zera), wówczas funkcja zwróci wartość wyrażenia  (w naszym przypadku Z), w przeciwnym razie wartością powrotną funkcji będzaie wartość wyrażenia  występującego po znaku  (w naszym przypadku [). 2. Wywołanie funkcji ogólnej OCZ w programie głównym nie powinno sprawić nam najmniejszych trudności. Na wydruku 2.9 pokazano kompleatny kod źródłowy modułu Unit09.cpp projektu Projekt_09.bpr. Wydruk 2.9. Moduł Unit09.cpp KPENWFGKQUVTGCOJ KPENWFGEQPKQJ RTCIOCJFTUVQR VGORNCVGENCUU6 6OCZ 6Z6[ ] TGVWTP Z [ !Z[ _  KPVOCKP ] FQWDNGZ[ EQWVUGVH KQUHKZGF  EQWVOCZ Z[ GPFN IGVEJ  TGVWTP _  36 C++Builder 6. Ćwiczenia W programie występuje dodatkowy szczegół, na który warto zwrócić uwagę. Mianowicie sposób formatowania liczb. W celu wyświetlenia wartości z większą liczbą cyfr po kropce, oddzielającej część całkowitą od części ułamkowej, wykorzystaliśmy metodę UGVH strumie- nia EQWV oraz metodę HKZGF (zwaną tutaj manipulatorem) klasy KQU. Z innymi sposobami przedstawiania liczb z użyciem funkcji składowych klasy KQU możemy zapoznać się studiując pliki pomocy. Ćwiczenie 2.15. Programiści C przyzwyczajeni są do używania makrodefinicji. Definicję funkcji ogólnej OCZ możemy zastąpić następującą makrodefinicją: FGHKPGOCZ Z[  Z [ !Z[ Warto jednak zwrócić uwagę, iż makrodefinicje nie mogą zmieniać wartości swoich pa- rametrów. Z tego względu pokazany sposób tworzenia makrodefinicji OCZ uważa się obecnie za przestarzały. Pro
Pobierz darmowy fragment (pdf)

Gdzie kupić całą publikację:

C++Builder 6. Ćwiczenia
Autor:

Opinie na temat publikacji:


Inne popularne pozycje z tej kategorii:


Czytaj również:


Prowadzisz stronę lub blog? Wstaw link do fragmentu tej książki i współpracuj z Cyfroteką: