web-dev-qa-db-fra.com

Fonction membre en ligne C++ dans un fichier .cpp

Je sais que les fonctions des membres en ligne, par définition, devraient être placées dans l'en-tête. Mais que se passe-t-il s'il n'est pas possible de mettre l'implémentation de la fonction dans l'en-tête? Prenons cette situation:

Fichier A.h

#pragma once
#include "B.h"

class A{
    B b;
};

Fichier B.h

#pragma once

class A; //forward declaration

class B{
    inline A getA();
};

En raison de la circulaire, je dois mettre la mise en œuvre de getA dans

B.cpp

#include "B.h"
#include "A.h"

inline A B::getA(){
    return A();
}

Est-ce que le compilateur inline getA? Si tel est le cas, quel mot clé en ligne est le mot clé (celui de l'en-tête ou celui du fichier .cpp)? Y a-t-il un autre moyen de mettre la définition d'une fonction membre intégrée dans son fichier .cpp?

62
Mat

Citant de C++ FAQ :

Note: Il est impératif que le la définition de la fonction (la partie entre le {...}) soit placée dans un fichier d'en-tête, sauf si la fonction est utilisé uniquement dans un seul fichier .cpp. Dans en particulier, si vous mettez le inline la définition de la fonction dans un fichier .cpp et vous l'appelez d'un autre .cpp fichier, vous obtiendrez une erreur "non résolue external" de l'éditeur de liens.

Le compilateur doit voir la definition de la fonction inline chaque fois qu'il trouve une utilisation quelconque de cette fonction inline. Cela est généralement possible si la fonction inline est placée dans un fichier d’en-tête.

Est-ce que le compilateur inline getA? 

Non, sauf lorsque l'utilisation de getA() est dans B.cpp même.

Si tel est le cas, quel mot clé en ligne est le mot clé (celui de l’en-tête ou celui du cpp)?

Meilleure pratique : uniquement dans la définition en dehors du corps de la classe.

Y a-t-il un autre moyen de mettre la définition d'une fonction membre intégrée dans son fichier cpp?

Non, au moins je ne sais pas.

63
Arun

Cela ne peut pas, en dehors du champ d'application de B.cpp. Le compilateur fonctionne sur une base par unité de compilation, c’est-à-dire qu’il compile chaque fichier .cpp individuellement. Par conséquent, s’il compile C.cpp, il n'aura pas le code pour getA () disponible et devra effectuer un appel de fonction demandez à l'éditeur de liens de le réparer (ou, si cela vous a vraiment pris par le mot et essayé de le mettre en ligne, il se retrouvera avec une erreur de l'éditeur de liens. inline a des qualités similaires à static).

La seule exception est LTCG, c’est-à-dire la génération de code à temps de lien, qui est disponible sur les nouveaux compilateurs.

Une approche dans ce cas consiste à avoir un autre fichier d’en-tête (parfois appelé fichiers * .inl) contenant le code en ligne.

EDIT: Pour ce qui est inline qui est pertinent - c’est celui de la définition de classe, c’est-à-dire du fichier d’en-tête. N'oubliez pas que de nombreux compilateurs ont leur propre idée de ce qui peut et devrait être intégré. Par exemple, gcc peut désactiver complètement l'inline (-O0), ou tout ce qui lui paraît utile (comme -O3).

16
EboMike

Je voudrais aller à ce sujet de la direction opposée.

N'ajoutez pas de déclarations inline à votre fonction (sauf si vous en avez aussi besoin).

La seule fois où vous devez ajouter la déclaration inline à une fonction/méthode est si vous définissez la fonction dans un fichier d’en-tête mais en dehors de la déclaration de classe.

X.h

class X
{
    public:
        int getX()   { return 4;} // No inline because it is part of the class.
                                  // The compiler knows that needs an inline tag
        int getY();
        int getZ();
};

inline
int X::getY()  { return 5;}       // This needs to be explicitly declared inline.
                                  // Otherwise the linker will complain about
                                  // multiple definitions in compilation units.

X.cpp

 // Never declare anything inline in the cpp file.

 int X::getZ() { return 6; }

Pour vous cas plus spécifique.
Supprimer toutes les spécifications en ligne. Ils ne font pas ce que vous pensez faire.

9
Martin York

Ces jours-ci, la plupart des compilateurs peuvent effectuer une mise en ligne au moment du lien, ainsi que du temps de compilation. Si votre fonction est susceptible de tirer parti de l’alignement en ligne, c’est ce que fait l’optimiseur Link Time.

Au moment où l'éditeur de liens y parvient, le statut en ligne de la sortie du compilateur n'est pas vraiment disponible, sauf que le compilateur marquera certains objets comme pouvant être collectionnés, par exemple parce qu'une instance en ligne ou un modèle de classe apparaît dans plusieurs unités de compilation, ou cela devrait générer une erreur lorsque plusieurs symboles partagent un nom, tel que la fonction principale étant définie deux fois. Rien de tout cela n'a d'influence sur le code réel qu'il va générer.

ISO/IEC 14882: 2014

Chaque programme doit contenir exactement une définition de chaque non-inline fonction ou variable utilisée par odr dans ce programme; pas de diagnostic Champs obligatoires. La définition peut apparaître explicitement dans le programme, elle peut se trouve dans la bibliothèque standard ou définie par l'utilisateur, ou (lorsque approprié), elle est définie implicitement (voir 12.1, 12.4 et 12.8). Une fonction en ligne doit être définie dans chaque unité de traduction dans laquelle elle est utilisée.

0
isnullxbh

Voici comment je l'ai fait.

Fichier A.h

#pragma once
#include "B.h"

class A {
    B b;
};

Fichier B.h

#pragma once

class B {
public:
    template<class T> inline T getA() {
        assert(NULL); // Use 'getA<A>()' template specialization only!
        return NULL;
    }
};

class A; // Forward declaration
template<> inline A B::getA<A>();

Fichier C.h

#pragma once
#include "A.h"
#include "B.h"

// Implement template specialization here!
template<> inline A B::getA<A>() { return A(); }

Incluez simplement le fichier "C.h" pour pouvoir utiliser la méthode getA (). La seule modification apportée au code d'origine est que la méthode getA () doit être définie comme publique au lieu de privée.

Cependant, comme beaucoup d'entre vous l'ont expliqué, cela n'est pas vraiment utile.

0
Pascal Viguié