Recherche…


Remarques

En C ++, comme en C, le compilateur et le processus de compilation C ++ utilisent le préprocesseur C. Comme spécifié dans le manuel GNU C Preprocessor, un fichier d'en-tête est défini comme suit:

Un fichier d'en-tête est un fichier contenant des déclarations C et des définitions de macro (voir Macros) à partager entre plusieurs fichiers sources. Vous demandez l'utilisation d'un fichier d'en-tête dans votre programme en l'incluant, avec la directive de prétraitement C '#include'.

Les fichiers d'en-tête ont deux objectifs.

  • Les fichiers d'en-tête système déclarent les interfaces à des parties du système d'exploitation. Vous les incluez dans votre programme pour fournir les définitions et les déclarations dont vous avez besoin pour appeler les appels système et les bibliothèques.
  • Vos propres fichiers d'en-tête contiennent des déclarations pour les interfaces entre les fichiers source de votre programme. Chaque fois que vous avez un groupe de déclarations associées et de définitions de macros dont la plupart ou la plupart sont nécessaires dans plusieurs fichiers sources différents, il est judicieux de créer un fichier d'en-tête pour ces fichiers.

Cependant, pour le préprocesseur C lui-même, un fichier d'en-tête n'est pas différent d'un fichier source.

Le schéma d'organisation des fichiers en-tête / source est simplement une convention standard et tenue en main établie par différents projets logiciels afin de fournir une séparation entre interface et implémentation.

Bien qu'il ne soit pas formellement appliqué par le standard C ++ lui-même, il est fortement recommandé de suivre la convention des fichiers en-tête / source et, dans la pratique, il est déjà presque omniprésent.

Notez que les fichiers d'en-tête peuvent être remplacés en tant que convention de structure de fichier de projet par la fonctionnalité à venir des modules, qui doit encore être prise en compte lors de l'écriture (par exemple C ++ 20).

Exemple de base

L'exemple suivant contiendra un bloc de code à scinder en plusieurs fichiers sources, comme indiqué par // filename comment.

Fichiers source

// 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;
}

Les fichiers d'en-tête sont ensuite inclus par d'autres fichiers sources qui souhaitent utiliser la fonctionnalité définie par l'interface d'en-tête, mais ne nécessitent pas de connaissances sur son implémentation (réduisant ainsi le couplage de code). Le programme suivant utilise l'en-tête my_function.h tel que défini ci-dessus:

// 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;
}

Le processus de compilation

Les fichiers d'en-tête faisant souvent partie d'un workflow de processus de compilation, un processus de compilation classique utilisant la convention d'en-tête / fichier source effectue généralement les opérations suivantes.

En supposant que le fichier d'en-tête et le fichier de code source se trouvent déjà dans le même répertoire, un programmeur exécutera les commandes suivantes:

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

Sinon, si vous souhaitez compiler d'abord main.cpp dans un fichier objet, puis ne lier que les fichiers objets comme étape finale:

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

g++ main.o my_function.o

Modèles dans les fichiers d'en-tête

Les modèles requièrent la génération de code à la compilation: une fonction basée sur un modèle, par exemple, sera effectivement transformée en plusieurs fonctions distinctes une fois qu'une fonction basée sur un modèle est paramétrée par utilisation dans le code source.

Cela signifie que la fonction de modèle, la fonction membre et les définitions de classe ne peuvent pas être déléguées à un fichier de code source distinct, car tout code qui utilisera une construction basée sur un modèle nécessite la connaissance de sa définition pour générer un code dérivé.

Ainsi, le code modélisé, s'il est placé en en-tête, doit également contenir sa définition. Un exemple de ceci est ci-dessous:

// 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
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow