Ricerca…


Osservazioni

In C ++, come in C, il compilatore C ++ e il processo di compilazione fanno uso del preprocessore C. Come specificato dal manuale del preprocessore GNU C, un file di intestazione è definito come segue:

Un file di intestazione è un file contenente dichiarazioni C e definizioni di macro (vedi Macro) da condividere tra diversi file di origine. Si richiede l'uso di un file di intestazione nel programma includendolo, con la direttiva di pre-elaborazione C '#include'.

I file di intestazione hanno due scopi.

  • I file di intestazione di sistema dichiarano le interfacce a parti del sistema operativo. Li includi nel tuo programma per fornire le definizioni e le dichiarazioni necessarie per richiamare le chiamate e le librerie di sistema.
  • I tuoi file di intestazione contengono dichiarazioni per le interfacce tra i file di origine del tuo programma. Ogni volta che si dispone di un gruppo di dichiarazioni correlate e definizioni macro tutte o la maggior parte delle quali sono necessarie in diversi file sorgente, è una buona idea creare un file di intestazione per loro.

Tuttavia, per il preprocessore stesso, un file di intestazione non è diverso da un file sorgente.

Lo schema di organizzazione del file di intestazione / sorgente è semplicemente una convenzione consolidata e standard impostata da vari progetti software al fine di fornire una separazione tra interfaccia e implementazione.

Sebbene non sia formalmente applicato dallo stesso standard C ++, è altamente raccomandato seguire la convenzione di file header / sorgente e, in pratica, è già quasi onnipresente.

Si noti che i file di intestazione possono essere sostituiti come una convenzione della struttura del file di progetto dalla funzione imminente dei moduli, che è ancora da considerare per l'inclusione in un futuro standard C ++ al momento della scrittura (ad esempio C ++ 20).

Esempio di base

L'esempio seguente conterrà un blocco di codice che deve essere suddiviso in diversi file di origine, come indicato da // filename commenti del // filename .

File sorgenti

// my_function.h

/* Note how this header contains only a declaration of a function.
 * Header functions usually do not define implementations for declarations
 * unless code must be further processed at compile time, as in templates.
 */

/* Also, usually header files include preprocessor guards so that every header
 * is never included twice.
 *
 * The guard is implemented by checking if a header-file unique preprocessor
 * token is defined, and only including the header if it hasn't been included
 * once before.
 */
#ifndef MY_FUNCTION_H
#define MY_FUNCTION_H

// global_value and my_function() will be
// recognized as the same constructs if this header is included by different files.
const int global_value = 42;
int my_function();

#endif // MY_FUNCTION_H

// my_function.cpp

/* Note how the corresponding source file for the header includes the interface  
 * defined in the header so that the compiler is aware of what the source file is 
 * implementing.
 *
 * In this case, the source file requires knowledge of the global constant
 * global_value only defined in my_function.h. Without inclusion of the header
 * file, this source file would not compile.
 */
#include "my_function.h" // or #include "my_function.hpp"
int my_function() {
  return global_value; // return 42;
}

I file di intestazione vengono quindi inclusi da altri file di origine che desiderano utilizzare la funzionalità definita dall'interfaccia dell'intestazione, ma non richiedono la conoscenza della sua implementazione (riducendo quindi l'accoppiamento del codice). Il seguente programma utilizza l'intestazione my_function.h come sopra definito:

// main.cpp

#include <iostream>       // A C++ Standard Library header.
#include "my_function.h"  // A personal header

int main(int argc, char** argv) {
  std::cout << my_function() << std::endl;
  return 0;
}

Il processo di compilazione

Poiché i file di intestazione sono spesso parte di un flusso di lavoro del processo di compilazione, un tipico processo di compilazione che utilizza la convenzione di file di intestazione / origine di solito eseguirà quanto segue.

Supponendo che il file di intestazione e il codice sorgente siano già nella stessa directory, un programmatore eseguirà i seguenti comandi:

g++ -c my_function.cpp       # Compiles the source file my_function.cpp
                             # --> object file my_function.o

g++ main.cpp my_function.o   # Links the object file containing the 
                             # implementation of int my_function()
                             # to the compiled, object version of main.cpp
                             # and then produces the final executable a.out

In alternativa, se si desidera compilare main.cpp in un file oggetto per primo e quindi collegare insieme solo i file oggetto come passo finale:

g++ -c my_function.cpp
g++ -c main.cpp

g++ main.o my_function.o

Modelli nei file di intestazione

I modelli richiedono la generazione del codice in fase di compilazione: una funzione basata su modelli, ad esempio, verrà trasformata in più funzioni distinte una volta parametrizzata una funzione basata su un modello mediante l'uso nel codice sorgente.

Ciò significa che la funzione template, la funzione membro e le definizioni di classe non possono essere delegate a un file di codice sorgente separato, poiché qualsiasi codice che utilizzerà un costrutto basato su modelli richiede la conoscenza della sua definizione per generare in genere un codice derivato.

Pertanto, il codice basato su modelli, se inserito nelle intestazioni, deve contenere anche la sua definizione. Un esempio di questo è qui sotto:

// templated_function.h

template <typename T>
T* null_T_pointer() {
  T* type_point = NULL; // or, alternatively, nullptr instead of NULL
                        // for C++11 or later
  return type_point;
} 


Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow