Questo è uno di quei "dovrebbe" piuttosto che "deve" tipi di standard di codifica. Il motivo è che dovresti scrivere un parser C ++ per forzarlo.
Una regola molto comune per i file di intestazione è che devono stare da soli. Un file di intestazione non deve richiedere che alcuni altri file di intestazione siano #inclusi prima di includere l'intestazione in questione. Questo è un requisito verificabile. Dato un po 'di intestazione casuale foo.hh
, il seguente dovrebbe compilare ed eseguire:
#include "foo.hh"
int main () {
return 0;
}
Questa regola ha conseguenze sull'uso di altre classi in alcune intestazioni. A volte queste conseguenze possono essere evitate dichiarando in avanti quelle altre classi. Questo non è possibile con molte classi di librerie standard. Non c'è modo di inoltrare una istanza di template come std::string
o std::vector<SomeType>
. Devi #include
di quelle intestazioni STL nell'intestazione anche se l'unico utilizzo del tipo è come argomento di una funzione.
Un altro problema riguarda cose che trascini involontariamente. Esempio: considera quanto segue:
file foo.cc:
#include "foo.hh"
#include "bar.hh"
void Foo::Foo () : bar() { /* body elided */ }
void Foo::do_something (int item) {
...
bar.add_item (item);
...
}
Qui bar
è un membro di dati di classe Foo
che è di tipo Bar
. Hai fatto la cosa giusta qui e hai #included bar.hh anche se sarebbe stato incluso nell'intestazione che definisce la classe Foo
. Tuttavia, non hai incluso le cose usate da Bar::Bar()
e Bar::add_item(int)
. Ci sono molti casi in cui queste chiamate possono portare a ulteriori riferimenti esterni.
Se analizzi foo.o
con uno strumento come nm
, sembrerà che le funzioni in foo.cc
chiamino tutti i tipi di materiale per i quali non hai fatto il #include
appropriato. Quindi dovresti aggiungere #include
direttive per quei riferimenti esterni accidentali foo.cc
? La risposta è assolutamente no. Il problema è che è molto difficile distinguere quelle funzioni chiamate incidentalmente da quelle che vengono chiamate direttamente.