Programowanie w Visual C++ 2010

Spis treści

Projekty wielomodułowe

Potrafisz już napisać działający program składający się z wielu różnych, stworzonych przez Ciebie i na Twoje potrzeby (por. wykład cz. 5), funkcji. Czasami jednak gdy tych funkcji jest zbyt dużo i w konsekwencji plik źródłowy (dotychczas wszystko pisaliśmy w jednym pliku .cpp) zaczyna przyjmować monstrualne rozmiary – trudno się w nim odnaleźć. Jak temu zaradzić?

Dodatkowe pliki źródłowe

Nieraz już korzystaliśmy z funkcji zdefiniowanych poza plikiem źródłowym zawierającym funkcję main(). Na przykład znamy doskonale funkcje sin() i cos() (zob. samouczek #6). Funkcje te należą do biblioteki systemowej <cmath>. Pamiętasz, jak sformułowaliśmy definicję biblioteki? Powiedzieliśmy, że jest to zbiór funkcji o określonym działaniu, gotowych do użycia w innych programach. Aby odciążyć główny plik naszego projektu, czasem warto stworzyć własny zbiór funkcji. Pierwszym krokiem ku temu jest podzielenie projektu na kilka plików źródłowych.

Prześledzimy proces dzielenia kodu źródłowego na przykładzie programu imitującego działanie pralki. Oto jego (sugerowana przeze mnie, zatem jedyna słuszna) implementacja:

#include <iostream>
using namespace std;

void wirowanie_delikatne()
{
   for(int i=0; i<5; i++)
      cout << "bzzz ";
   cout << endl;
   cout << "Mozesz wyciagnac i rozwiesic pranie" << endl;
}

void wyzymanie_gatek()
{
   for(int i=0; i<8; i++)
      cout << "pfffrr ";
   cout << endl;
   cout << "Gatki zostaly wyzete. Mam nadzieje, ze sie nie rozciagnely." << endl;
}

void pranie_wstepne()
{
   for(int i=0; i<10; i++)
      cout << "szur ";
   cout << endl;
   cout << "koniec prania" << endl;
   wirowanie_delikatne();
}

void pranie_brudow()
{
   for(int i=1; i<=20; i++)
   {
      cout << "szuru buru" << endl;
      if(i%5==0)
         cout << "Frania wie, ze smieci niewyniesione! Do roboty!" << endl;
   }
   cout << "koniec prania" << endl;
   wyzymanie_gatek();
}

int main()
{
   int wybor=0;
   cout << "PRALKA FRANIA" << endl;
   while (true)
   {
      cout << "1 - Pranie wstepne" << endl;
      cout << "2 - Pranie brudów" << endl;
      cout << "3 - Wirowanie delikatne "<< endl;
      cout << "4 - Wyżymanie gatek" << endl;
      cout << "5 - Koniec" << endl;

      cin >> wybor;
      cout << endl;

      if (wybor == 1)
         pranie_wstepne();
      else if (wybor == 2)
         pranie_brudow();
      else if (wybor == 3)
         wirowanie_delikatne();
      else if (wybor == 4)
         wyzymanie_gatek();
      else
         return 0;

      cout << endl;
   }
   return 0;
}
Stwórz nowy projekt, dodaj doń plik źródłowy i umieść w nim powyższy kod. Zapoznaj się z działaniem programu.

Tak skonstruowany program zdaje się być nieco bałaganiarski i przydługi. Chcemy go koniecznie uporządkować i skrócić! Dodajemy zatem do projektu nowy plik .cpp o nazwie programy.cpp (jeśli nie pamiętasz, jak to zrobić, opis tego procederu znajdziesz w drugim samouczku) i wklejamy do niego wszystkie funkcje oprócz main().

Ajajaj! Wszystkie odwołania do obiektu cout zostały podkreślone na czerwono. Rzućmy okiem na opis błędu: Dodatkowy plik .cpp I Przy próbie kompilacji (CTRL + F7) w panelu Output pojawia się informacja error C2065: 'cout' : undeclared identifier. No tak! Z tym błędem mieliśmy już do czynienia w samouczku #4! :-) Wystarczy zatem dodać na początku pliku programy.cpp dwie linijki, otrzymując ostatecznie taką oto postać tegoż pliku:

#include <iostream>
using namespace std;

void wirowanie_delikatne()
{
   for(int i=0; i<5; i++)
      cout << "bzzz ";
   cout << endl;
   cout << "Mozesz wyciagnac i rozwiesic pranie" << endl;
}

void wyzymanie_gatek()
{
   for(int i=0; i<8; i++)
      cout << "pfffrr ";
   cout << endl;
   cout << "Gatki zostaly wyzete. Mam nadzieje, ze sie nie rozciagnely." << endl;
}

void pranie_wstepne()
{
   for(int i=0; i<10; i++)
      cout << "szur ";
   cout << endl;
   cout << "koniec prania" << endl;
   wirowanie_delikatne();
}

void pranie_brudow()
{
   for(int i=1; i<=20; i++)
   {
      cout << "szuru buru" << endl;
      if(i%5==0)
         cout << "Frania wie, ze smieci niewyniesione! Do roboty!" << endl;
   }
   cout << "koniec prania" << endl;
   wyzymanie_gatek();
}
 

Ha! Teraz programy.cpp kompiluje się bez zająknięcia! Pełni nadziei czym prędzej uruchamiamy program... I klapa. Pojawia się kolejny błąd: error C3861: 'pranie_wstepne': identifier not found.

Dołączając któryś z elementów biblioteki języka C stosowaliśmy dyrektywę #include, po której dopisywaliśmy nazwę żądanej podbiblioteki (w nawiasach trójkątnych). Podobnie musimy postąpić, chcąc dołączyć nasz zbiór funkcji. Nie można (właściwie można, ale to bardzo nieroztropne posunięcie) jednak dołączyć do projektu pliku .cpp, używając tej dyrektywy. Z pomocą przychodzą nam pliki nagłówkowe i deklaracje funkcji.

Dodatkowe pliki nagłówkowe

Plikiem nagłówkowym nazywamy plik o rozszerzeniu .h, który zawiera deklaracje funkcji.
Dobrze jest, gdy plik nagłówkowy, zawierający deklaracje funkcji, ma taką samą nazwę, jak plik źródłowy .cpp zawierający definicje tych funkcji.

Spróbujmy stworzyć plik nagłówkowy dla naszego przykładu. Wiemy już, że powinien nosić on nazwę programy.h. Dodajemy go do projektu w analogiczny sposób, jak programy.cpp:

  1. Klikamy prawym przyciskiem myszy na Header Files w panelu Solution Explorer.
  2. Wybieramy Add|New Item.
  3. W nowo otwartym oknie wybieramy rodzaj pliku – w tym wypadku Header File (.h) i wpisujemy jego nazwę. Upewnijmy się, że wszystkie pliki (źródłowe i nagłówkowe) znajdują się w tym samym katalogu, co plik z funkcją main().

W efekcie powstaje nowy, pusty plik .h.

Zastanówmy się teraz, co umieścić w takim pliku. Czy będziemy potrzebowali załączyć do niego choćby bibliotekę <iostream>? Niekoniecznie. Jedyne, co musi znaleźć się w tym pliku to deklaracje funkcji odpowiedzialnych za funkcjonalność naszej pralki (por. cz. 5 wykładu):

void wirowanie_delikatne();
void wyzymanie_gatek();
void pranie_wstepne();
void pranie_brudow();

Teraz wystarczy już tylko dopisać na początku plików pralka.cpp oraz programy.cpp linijkę:

#include "programy.h"

...i pralka pierze, że ho ho! :-)

Być może zastanawia Cię, dlaczego po dyrektywie #include nazwy bibliotek pisaliśmy w nawiasach ostrych, a nazwę stworzonego przez nas pliku źródłowego zawarliśmy w cudzysłowach. Otóż nawiasy ,,informują'' kompilator, że pliku z deklaracjami funkcji powinien szukać w katalogu systemowym, z kolei cudzysłów odsyła go w tych poszukiwaniach do katalogu z aktualnym projektem.
Spróbuj napisać prosty kalkulator czterodziałaniowy. Pętlę główną programu możesz inspirować funkcją main() z przykładu. Funkcje odpowiadające za działania umieść w dodatkowym pliku źródłowym.

Jeszcze więcej plików...

Przyjrzyjmy się, jak jeszcze bardziej ,,rozdrobnić'' kod programu na dodatkowe pliki (może nie w tym przypadku, ale czasem naprawdę warto będzie tak robić). W tym celu zmodyfikujemy ponownie nasz przykład (obiecuję, że po raz ostatni!).

Funkcje wirujące przeklej z programy.cpp do nowego pliku wirowania.cpp. Stwórz odpowiedni plik nagłówkowy.

Zauważmy, że z funkcji zdefiniowanych teraz w wirowanie.cpp korzystamy zarówno w pliku z programami, jak i w głównym pliku naszego projektu. Czy oznacza to, że w obydwu powinniśmy dopisać #include "wirowania.h"? W tym wypadku moglibyśmy tak zrobić. Jednak w nieco bardziej zaawansowanych programach opartych na obiektowości (sem. II) takie wielokrotne dołączanie tego samego pliku nagłówkowego spowoduje błąd kompilacji. Dlatego też bezpiecznym i eleganckim nawykiem będzie tworzenie plików nagłówkowych według następującego schematu:

#pragma once

/*
tutaj znajduje się zawartość Twojego pliku nagłówkowego
- te instrukcje zostaną wykonane tylko wtedy,
gdy plik nazwaPliku.h jest załączany po raz pierwszy
*/

Taka budowa pliku nagłówkowego zabezpieczy Twoją bibliotekę przed kilkukrotnym dołączaniem zawartości tego samego pliku do programu.

Stosując ów schemat do pliku programy.h, otrzymamy następujący wynik:

#pragma once

#include "wirowania.h"

void pranie_wstepne();
void pranie_brudow();

Podsumowanie

Oto co powinniśmy zapamiętać z tego krótkiego samouczka.

  • Jeżeli na potrzeby programu chcemy napisać kilka funkcji ,,podręcznych'', z których korzystamy np. w funkcji main(), nie implementujemy ich w głównym pliku projektu, lecz w dodatkowym pliku .cpp.
  • Dla każdego dodatkowego pliku .cpp tworzymy odpowiadający mu plik nagłówkowy .h o tej samej nazwie. Umieszczamy w nim deklaracje funkcji.
  • Każdy z plików nagłówkowych zawierających deklaracje funkcji, których pragniemy użyć w funkcji main(), musimy dołączyć do głównego pliku projektu przy pomocy dyrektywy #include według następującego schematu:
    #include "nazwa_pliku.h"
  • Jeżeli w dodatkowym pliku źródłowym używamy funkcji z innych plików naszego autorstwa, powinniśmy je dołączyć do odpowiadającego mu pliku nagłówkowego.
  • Tworząc plik nagłówkowy, nie zapominamy o dyrektywie #pragma once.
CC By 3.0
Copyright © 2011-2016 by Jowita Hącia [Last update: 2017-02-01 17:17:06]
This work is licensed under a Creative Commons Attribution 3.0 Unported License