W tej lekcji opiszę jak w Dev C++ robić projekty składające sie z wielku plików.

Na początek powiedzmy sobie, o rodzajach plików jakie można dołączyć do projektu. Otóż mogą to być pliki z kodem źrółowym *.cpp, pliki nagłówkowe *.h, oraz pliki zasobów *.rc

Pliki *.cpp

Pliki z kodem źródłoym o rozszerzeniu *.cpp to pliki, które będą najczęściej występować w projekcie, pisze się w nich ciała funkcji oraz deklaruje zmienne. W projekcie może się znajdować, wiele takich plików, zwykle dzielimy funkcje tematycznie, czyli według tego co one robią i umieszczamy je w odpowiednim pliku *.cpp, dzięki temu unikamy bałaganu w projekcie. Np. w jednym pliku, możemy umieścić funkcje odpowiedzialne za wygląd graficzny, w drugim podstawowe dla danego programu, a w trzecim odpowiedzialne za wczytywanie i zapisywanie ustawień z i do programu.

Pliki nagłówkowe *.h

Ten rodzaj plików słuzy do deklaracji w nich: struktur, klas, typów i funckji. W tym pliku mogą występować tylko deklaracje!

Pliki zasobów *.rc

Ten rodzaj plików poznasz bliżej w podstawach kursu WinAPI. W nim możemy dołączać różne zasoby, np. ikony, bitmapy lub inne pliki. W projekcie możemy dołączyć wiele takich plików, wszystkie zasoby w tych plikach i tak zostaną zawarte w jednym pliku wykonywalnym, więc nie ma róznicy czy dołączymy dwie ikony w jednym pliku *.rc, czy dołączymy ikonę w oddzielnym pliku *.rc

Przykładowa budowa projektu

Weźmy dla przykładu projekt, który ostatnio napisałem:

Przeanalizujmy jego budowę. Zawsze zaczynamy od jakiegoś pliku głównego w projekcie. Jest nim "shell.cpp", na samym końcu. W tym pliku jest funkcja main(), oraz najważniejsze zmienne w programie, zmienne globalne, jest to więc plik wejściowy w projekcie, od którego zaczyna się wszystko.

Dalej pierwszym plikiem jest "bar.h", jest tam zawarta deklaracja klasy o nazwie bar. W pliku "bar.cpp" są jej podstawowe funkcje, konstruktor, destruktor itd. W pliku "bar_buttons.cpp", są zawarte funkcje z klasy bar, które są odpowiedzialne za pracę z przyciskami("buttons"). W pliku "bar_clock.cpp" są funkcje sterujące zegarem w klasie bar. Plik "bar_tray.cpp" to funkcje odpowiedzialne za tray w klasie bar i plik "bar_wnds.cpp" zawiera funkcje związane z oknami w klasie Bar. Jak widać mamy klasę bar zadeklarowaną w pliku bar.h i szereg plików z kodem(ciałami funkcji), w których znajdują się funkcje z tej klasy, podzielone tematycznie.

Następnie mamy klasę desktop zadeklarowaną w pliku "desktop.h". Plik "desktop.cpp" to podstawowe funkcje tej klasy, a plik "desktop_loadsave.cpp" zawiera funkcje zajmujące się łądowaniem i odczytywaniem pewnych rzeczy z plików.

W kolejnych plikach mamy jeszcze dwie klasy file_manager w "file_manager.h", "file_manager.cpp" i klasa settings w plikach "settings.h", "settings.cpp".

W projekcie jest jeszcze plik "res.rc" zawierający zasoby aplikacji.

Ten przykład obrazuje nam pisanie aplikacji obiektowej w wielu plikach. Teraz musimy miec świadomość, że z tych wszystkich plików zostanie zbudowany tylko 1 plik *.exe. Wszystkie plik zostaną w pewnym sensie połączone w całość!

Jeden plik wykonywalny - odzielnie pliki

Teraz trzeba sobie trochę powiedzieć na temat pojedynczego pliku z kodem źródłowym *.cpp, w kontekście całego projektu. Otóż zwykle na początku pliku dołączamy jakieś pliki nagłówkowe. To jakie dołączamy zależy od tego, co bedziemy pisać w tym pliku. Przykładowo w pliku "bar.cpp" dołączam na początku pliki "bar.h" i "settings.h", gdyż w tym pliku "bar.cpp", będę korzystał z rzeczy zadeklarowanych w "bar.h", a także kilku elementów z klasy w "settings.h", gdybym w którejś z funckji znajdujących sie w pliku "bar.cpp" potrzebował się odwołać się do jakiegoś elementu zadeklarowaneg w klasie "dekstop.h", musiałbym także dołączyć ten plik, gdyż kompilator nie wiedziałby jak wygląda ta klasa. Pliki dołączamy dyrektywą #include "plik.h/.cpp"

Tu dochodzimy do jednego wniosku, pomimo tego, że wszystkie pliki *.cpp tworzą jeden cały program, to nie widzą one swojej zawartości na wzajem, każdy plik *.cpp musimy potraktować indywidualnie, pomimo tego, że wszystkie one tworzą 1 program. Każdemu musimy dołączyć oddzielnie pliki nagłówkowe, zmienne globalne zadeklarowane w jednym z plików *.cpp nie są jasno widoczne w innym pliku *.cpp, każdy z nich jest w pewnym sensie innym programem, a raczej modułem programu.

extern w projekcie

Jeżeli chodzi o funkcje, to nie ma problemu, bo wystarczy umiescić jej deklaracje w jednym z plików nagłówkowych, a będzie ona widoczna we wszystkich modułach, w których dołączony jest plik nagłówkowy z deklaracją. Ze zmiennymi globalnymi jest trochę inaczej, nie ma ich deklaracji, zmienne deklaruje sie w jednym z plików *.cpp, ale jest sposób aby były widoczne w innym, otóż trzeba zastosować tytułowe extern, ten przedrostek mówi, że zmienna jest zadeklarowana w innym pliku *.cpp Dla przykładu w pliku "shell.cpp" mamy:

int zmienna=
23
;
//w pliku "shell.cpp"

i teraz aby używac tej zmiennej w innym pliku, np. "bar.cpp", trzeba w "bar.cpp" zadeklarować, że zmienna taka jest utworzona w innym pliku źródłowym i już, nie musimy okreslać, w jakim wystarczy napisać extern, kompilatorowi to wystarczy.

extern int zmienna;
//w pliku "bar.cpp" oznacza, że używamy zmiennej "zmienna" z innego pliku

Słówko o plikach nagłówkowych

Jak wiadomo w plikach tych piszemy deklaracje klas, funkcji itd. Pliki te dołączamy do plików *.cpp, ale jest pewna niedogodność związana z dołączaniem takich plików, otóż dany plik można dołączyć tylko raz na całą kompilację, tzn, że gdy dołączymy plik "settings.h" do "settings.cpp" i jeszcze do "bar.cpp" to wystapi błąd. Oczywiście ciężko by się pisało, gdyby tak było rzeczywiście w praktyce. Zaczęto sobie radzić z tym problemem na 2 sposoby, pierwszy starszy to odpowiednie użycia instrukcji #define, #ifdef, #endif itd. w efekcie czego przy kompilacji pojedynczy plik był dołączany tylko raz pomimo tego, że dołączyliśmy do w kilki plikach *.cpp Takie rozwiązania możemy znaleźć w plikach WinAPI.

Widząc, że takie operacje są uciążliwe, nowsze kompilatory obsługują specjalną dyrektywę dla linkera, która właśnie dodana na początku pliku nagłówkowego, mówi kompilatorowi, że ten plik powinien być dodany tylko raz, pomimo tego, że jest jest dołączony do kilku plików *.cpp Wygląda ona tak:

#pragma once

Tutaj możemy pobrać przykładowy projekt obiektowy wielo-plikowy w Dev C++. Ważniejsze elementy postaram się opisać w komentarzach.

Wejść na stronę:     Ilość osób online:
Prawa autorskie © 2008 crayze. Wszelkie prawa zastrzeżone.
crayze7@gmail.com