Pour en savoir plus, lisez ce texte sur la mécanique de compilation en C++. Vous apprécierez peut-être aussi ../AuSecours/specifications-entreposage.html qui discute de questions connexes
C++, comme C, préconise la compilation séparée. En ce sens, chaque fichier source (typiquement, un fichier portant l'extension .cpp) est compilé séparément des autres, puis les fichiers objets résultants (.o, .obj, .a, .lib, etc.) sont assemblés en un binaire (.exe, .dll, .so, etc.) par un mécanisme nommé l'édition des liens.
C++ exige qu'il n'y ait qu'une seule définition pour chaque chose, tout en tolérant qu'il y ait plusieurs déclarations pour une même entité. Pour cette raison, un fichier source est en violation d'ODR s'il a plus d'une définition pour un même nom, et ce même si les deux définitions sont identiques. Notez qu'une violation d'ODR est techniquement un cas de comportement indéfini, alors mieux vaut les éviter!
Par exemple, ci-dessous, le programme vilain.cpp est en violation d'ODR à cause de la double définition de la variable x et de la fonction f(). Notez que y ne pose pas de problème car les deux variables de ce nom ne sont pas définies au même niveau hiérarchique, ce qui évite les conflits de noms. Notez aussi que g() ne pose pas de problème à la compilation (l'appel respecte la signature annoncée par son prototype), mais il faudra qu'une définition (unique) soit rendue disponible au moment de l'édition des liens pour que cette étape de génération de code soit un succès :
int x = 3,
y = 4;
int f(int n) {
return n + x;
}
int g(int);
#include <iostream>
int main() {
using namespace std;
int y = f(-2);
cout << g(y) << endl;
}
float x = 3.14159f; // <-- violation d'ODR
int f(int n) { // <-- violation d'ODR (que le corps de la fonction soit le même qu'avant ou pas)
return n * n;
}
Sachant de l'inclusion des fichiers d'en-têtes est lexicale, il faut comprendre ce qui peut être placé (ou non) dans un tel fichier pour éviter les erreurs. Les règles sont simples, au fond : un .h ne peut contenir que des déclarations ou des définitions inline, donc des éléments qui ne risquent pas de causer de violations d'ODR :
|
|
Il ne faut donc pas mettre dans un .h les choses suivantes :
Dans ces cas, le fait d'inclure le même .h dans deux .cpp d'un même projet entraînera une double définition de l'entité « offensante », donc une violation d'ODR. |
|
Quelques liens pour enrichir le propos :