Zmora zależności

W małych programach autorzy nie zwracają szczególnej uwagi na listy dołączanych plików nagłówkowych. Czegoś brakuje - to dorzucamy kolejne #include i tyle.

W dużych systemach tego typu lekkie podejście owocuje prostą konsekwencją: po drobnej korekcie w rzadko używanej klasie, następuje totalna wielogodzinna rekompilacja wszystkiego. Bo autor często używanego nagłówka z jakichś powodów dołączył ten rzadko używany albo autorzy całej serii plików robili copy&paste i dołączali nagłówek choć go nie używali.

Aby tego uniknąć należy pamiętać o następujących prostych sprawach:

  • kilka małych plików nagłówkowych jest zazwyczaj lepsze niż jeden duży - nie należy upychać w jednym nagłówku kilku niezwiązanych tematycznie grup funkcji i klas;
  • należy dołączać tylko to co jest nam potrzebne i nic więcej - nawet jeśli oznacza to dołączenie dwóch "szczegółowych" nagłówków a nie jednego zbiorczego;
  • w plikach nagłówkowych - o ile tylko jest to możliwe - należy unikać niepotrzebnego dołączania zewnętrznych headerów.

Może komentarz na temat ostatniej rady - w szczególności, często zamiast dołączyć nagłówek deklarujący jakąś klasę wystarczy napisać jej zapowiedź (class SomeClass;) a sam nagłówek klasy dołączyć jedynie w pliku implementacji (cpp czy też cxx). Może to wymagać drobnych korekt API (po takiej zapowiedzi można wymieniać jako parametry i atrybuty wskaźniki i referencje do takiej klasy, nie można jednak wstawiać pełnych obiektów takiego typu ani (w pliku nagłówkowym) wywoływać ich metod. Życie może też nam utrudnić kompilator - np. Visual C++ potrzebuje pełnej deklaracji klasy w pliku nagłówkowym gdy używamy jako atrybutów obiektu template opartych na tej klasie (np. auto_ptr<SomeClass>).

Z omawianym tematem silny związek ma tzw. idiom pimpl (pointer to implementation). Nasza klasa jedynie definiuje publiczny interfejs oraz zapowiada klasę która faktycznie implementuje wszystkie operacje - oraz przechowuje do niej wskaźnik. W ramach implementacji wszystkie metody przekazują wywołania do klasy implementacyjnej. Stosując tę technikę możemy swobodnie modyfikować atrybuty klasy implementacyjnej i dorzucac do niej funkcje prywatne - nie wymuszając rekompilacji kodu użytkowników (a także nie musząc przekazywać użytkownikom szczegółów implementacyjnych - plik nagłówkowy klasy implementacji nie jest przy używaniu biblioteki potrzebny).

komentarze obsługiwane przez Disqus