Organizacja kodu

Funkcje i moduły

Program – sekwencja instrukcji posiadająca pewną strukturę. Funkcje oraz zmienne mogą być grupowane na dwa sposoby:

  1. Fizyczny – moduły (jednostki translacji) reprezentowane przez pliki, które mogą być kompilowane niezależnie od siebie

  2. Logiczny

  • Struktury, klasy (paradygmat obiektowy)

  • Przestrzenie nazw

Pliki nagłówkowe i źródłowe

Pliki nagłówkowe (*.h, *hpp) zawierają:

  • Deklaracje stałych

  • Deklaracje zmiennych globalnych

  • Deklaracje funkcji

  • Deklaracje typów

Pliki źródłowe (*.cpp) zawierają właściwy kod programu, w tym:

  • Implementację funkcji

  • Implementację typów

mathematics.h

int square(int x);
int minus(int x, int y);
int plus(int x, int y);

mathematics.cpp

int square(int x)
{
  return x * x;
}

int minus(int x, int y)
{
  return x – y;
}

int plus(int x, int y)
{
  return x + y;
}

Preprocesor

Dzięki zastosowaniu preprocesora kod programu może zostać zmodyfikowany zanim zostanie skompilowany dzięki:

  • dołączaniu zawartości plików nagłówkowych - #include

  • kompilacji warunkowej - #if defined #else #endif

  • kompilacji warunkowej plików nagłówkowych - #ifndef XX #define XX #endif

  • definicjom - #define XX YY #if XX < YY #elseif

Bariery #include

Produkcyjne aplikacje języka C++ korzystają zazwyczaj z wielu plików nagłówkowych, w których niejednokrotnie dochodzi do włączania całych grup kolejnych grup plików nagłówkowych. Należy unikać wielokrotnego pośredniego włączania tego samego pliku nagłówkowego do kompilacji. W tym celu należy korzystać z odpowiednich dyrektyw preprocesora.

#ifndef HDR1_HPP
#define HDR1_HPP

// właściwa zawartość pliku nagłówkowego

#endif

Słowo kluczowe extern

Słowo kluczowe extern umożliwia zdefiniowanie zmiennej, która może być wykorzystywana w różnych modułach programu, ale ma występować w jednym egzemplarzu. Ma być zmienną globalną dla całego programu.

// global.h
#ifndef GLOBAL_H
#define GLOBAL_H

#include <string>

extern int x;
extern std::string s;

#endif

// global.cpp
#include <string>
int x = 7;
std::string s = "Kangur";

// main.cpp
#include <iostream>
#include "global.h"
using namespace std;

int main()
{
  cout << "x=" << x << " s=" << s << endl;
}

Przestrzenie nazw

Przestrzenie nazw służą logicznemu grupowaniu typów i funkcji.

W przestrzeniach nazw możemy umieszczać dowolne symbole. Użycie symbolu poza przestrzenią nazw, do której należy dany symbol, wymaga poprzedzenia go odpowiednim przedrostkiem. Unikany jest wówczas konflikt nazw oraz jawnie określana jest przynależność symbolu do określonej przestrzeni.

namespace A
{
  typedef ... String; // definicja typu A::String
  void foo(String); // definicja funkcji A::foo(A::String)
}
namespace B
{
  typedef ... String; // definicja typu B::String
  void foo(String); // definicja funkcji B::foo(B::String)
}

A::String s1; // tworzy zmienną typu String zadeklarowanego w przestrzeni A
B::String s2; // tworzy zmienną typu String zadeklarowanego w przestrzeni B

A::foo(s1); // wywołuje funkcję foo() zadeklarowaną w przestrzeni A
B::foo(s2); // wywołuje funkcję foo() zadeklarowaną w przestrzeni B

foo(s1); // A::foo(s1)
foo(s2); // B::foo(s2)

Słowo kluczowe using

Słowo kluczowe using umożliwia uniknięcie wielokrotnego stosowania operatora zakresu ::using może zostać użyte na dwa sposoby, jako:

  1. deklaracja using – symbol określonej przestrzeni nazw staje się dostępny lokalnie

using A::String;
  1. dyrektywa using – umożliwia zastosowanie wszystkich symboli danej przestrzeni nazw bez użycia operatora zakresu

using namespace A;
using namespace std;

Aliasy przestrzeni nazw

Aliasy umożliwiają użycie skrótów dla długich przestrzeni nazw.

namespace American_Telephone_and_Telegraph
{
  // ...
}

namespace ATT = American_Telephone_and_Telegraph;
ATT::String s1 = "Grieg";
ATT::String s2 = "Nielsen";