web-dev-qa-db-fra.com

Définition des fonctions C++ dans les fichiers d'en-tête

Je me demande si c'est une bonne pratique de stocker des fonctions régulières c ++, pas des méthodes (celles dans les classes) dans des fichiers d'en-tête.

Exemple:

#ifndef FUNCTIONS_H_INCLUDED
#define FUNCTIONS_H_INCLUDED

int add(int a, int b)
{
   return a + b;
}

#endif

Et utilisez-le comme ça:

#include <iostream>
#include "Functions.h"

int main(int argc, char* args[])
{
    std::cout << add(5, 8) << std::endl;
    return 1;
}

Est-ce une bonne pratique? Merci

6
Nobody

Si vous souhaitez utiliser une fonction dans plusieurs fichiers source (ou plutôt, unités de traduction ), vous placez une fonction déclaration (c'est-à-dire un prototype de fonction) dans le fichier d'en-tête, et le definition dans un fichier source.

Lorsque vous générez, vous compilez d’abord les fichiers source en fichiers objet, puis vous liez les fichiers objet à l’exécutable final.


Exemple de code:

  • En tête de fichier

    #ifndef FUNCTIONS_H_INCLUDED
    #define FUNCTIONS_H_INCLUDED
    
    int add(int a, int b);  // Function prototype, its declaration
    
    #endif
    
  • Premier fichier source

    #include "functions.h"
    
    // Function definition
    int add(int a, int b)
    {
        return a + b;
    }
    
  • Deuxième fichier source

    #include <iostream>
    #include "functions.h"
    
    int main()
    {
        std::cout << "add(1, 2) = " << add(1, 2) << '\n';
    }
    

La façon dont vous le construisez dépend beaucoup de votre environnement. Si vous utilisez un IDE (comme Visual Studio, Eclipse, Xcode, etc.), vous placez tous les fichiers dans le projet aux endroits appropriés.

Si vous construisez à partir de la ligne de commande, par exemple, Linux ou OSX, alors vous aimez

$ g++ -c file1.cpp
$ g++ -c file2.cpp
$ g++ file1.o file2.o -o my_program

L'indicateur -c indique au compilateur de générer un fichier objet et de lui donner le même nom que le fichier source, mais avec un suffixe .o. La dernière commande relie les deux fichiers objet pour former l'exécutable final et le nomme my_program (c'est ce que fait l'option -o et indique le nom du fichier de sortie).

21

Non. Si vous importez le même en-tête à partir de deux fichiers, vous obtenez une redéfinition de la fonction.

Cependant, c'est habituel si la fonction est inline. Chaque fichier a besoin de sa définition pour générer du code, de sorte que les gens la mettent généralement en-tête.

L'utilisation de static fonctionne également car les fonctions statiques ne sont pas exportées à partir d'un fichier objet et ne peuvent donc pas interférer avec d'autres fonctions portant le même nom pendant la liaison.

Il est également correct de définir les fonctions membres dans l'en-tête class, car la norme C++ les considère comme inline.

8
Alexey Shmalko

Après le prétraitement, chaque fichier source contiendra le fichier d’en-tête. Ensuite, au stade de la liaison, vous obtiendrez une erreur de définition multiple, car vous aurez plusieurs définitions de la même fonction.

Utiliser inline ou static éliminera l'erreur de liaison. Sauf si vous souhaitez que la fonction soit inline, il est préférable de declare la fonction dans l'en-tête et define it dans un seul fichier source et de le lier.

Si vous déclarez la fonction en tant que inline, chacun de ses appels de fonction dans le fichier source sera remplacé par le code contenu dans la fonction inlined. Donc, il n'y a pas de symbole supplémentaire défini.

Si vous déclarez la fonction en tant que static, le symbole de la fonction ne sera pas exporté à partir de l'unité de traduction. Par conséquent, aucun symbole en double.

0
Nikopol