IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

Séparer prototypes et définitions


Sujet :

C++

  1. #1
    Invité
    Invité(e)
    Par défaut Séparer prototypes et définitions
    Bonjour,

    J'aimerais savoir s'il est possible de séparer prototypes (.hpp) et définitions (.cpp) des méthodes inline; templates; et virtuel d'une classe A.

    Certains disent que c'est possible, d'autre le déconseillent fortement. Qu'en pensez vous ? Merci d'avance pour vos réponse.

  2. #2
    Membre éprouvé
    Avatar de méphistopheles
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    1 551
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 1 551
    Points : 1 218
    Points
    1 218
    Par défaut
    la plupart des compilateurs ne le gèrent pas. de toutes façon, les fichier .cpp servent surtout pour moi à être compilé indépendamment, ce qui n'est évidemment pas possible pour un template ou une fonction inline.

    Bref. Le plus simple est pour moi, c'est de mettre tes définitions dans un autre .hpp que tu include dans le .hpp de ta classe principale si tu veux les séparer...

    Bonne chance

  3. #3
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 630
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 630
    Points : 30 699
    Points
    30 699
    Par défaut
    Salut,

    C'est possible pour les fonction inlines et pour les fonctions de classes template, mais sous certaines conditions

    C'est très fortement recommandé pour les fonctions virtuelles.

    Les conditions auxquelles il est possible de définir les fonctions inline et les fonctions de classes template sont identiques (parce qu'elle suivent un raisonnement sensiblement): le code d'implémentation doit être disponible pour chaque appel de la fonction.

    En effet:
    Pour implémenter l'appel d'une fonction inline, le compilateur doit... disposer du code de la dite fonction afin de remplacer l'appel.

    En ce qui concerne les fonctions de classes template, le compilateur ne peut pas créer le code exécutable correspondant tant qu'il n'a pas connaissance de la taille... de tous les types utilisés pour paramétrer les fonctions, chose qu'il ne peut avoir que... quand on crée effectivement une instance particulière (dans le sens de "paramétrée avec un ou des types particuliers) de la classe.

    Note que, quoi qu'il en soit, tu devra expliciter le fait que les fonctions sont inlines, si tu le fais de cette manière

    Enfin, en ce qui concerne les fonctions virtuelles, le propre de ces fonctions est de passer par la vtable de la classe parent, et elles ne peuvent donc pas être inline.

    De plus, si tu place leur définition ailleurs que dans un fichier d'implémentation séparé, tu auras beau les entourer de tous les gardes anti inclusion multiple que tu voudra, tu arrivera au mieux à éviter qu'elles soient définies deux fois dans la même unité de compilation, mais tu aura le plus grand mal à éviter qu'elles ne soient définie dans plusieurs unités de compilation (même si ce n'est qu'une seule fois par unité de compilation).

    Quoi qu'il en soit, la règle de la définition unique sera bafouée, et l'éditeur de liens ne sera plus en mesure de faire son travail correctement

  4. #4
    Invité
    Invité(e)
    Par défaut
    Merci pour vos réponse,

    Mais si j'ai dans un même fichier (A.hpp) les prototypes et définitions (toujours séparé) d'une même classe A :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
     
    #ifndef FILE__A
    #define FILE__A
     
    class A
    {
    	public:
    		A();
    		bool uu()
    		inline int tt();
    		template<typename T> T ch(T h = 0);
     
    	protected:
    		bool u;
    		int t;
    		int c;
     
    };
     
    A::A() : u(true), t(8), c(1)
    {
     
    }
     
    bool A::uu()
    {
    	return u;
    }
     
    inline int A::tt()
    {
    	return t;
    }
     
    template<typename T> T A::ch(T h)
    {
    	if(h == 1) return h + c;
    }
     
    #endif //FILE__A
    Et que j'ai deux fichiers sources (.cpp) qui incluent ce même fichier. Il ne risquent pas d'avoir un problème de linker ? Comment faire dans ce cas "particulier" ?

    Merci encore

  5. #5
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 630
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 630
    Points : 30 699
    Points
    30 699
    Par défaut
    Citation Envoyé par Abdelite Voir le message
    Merci pour vos réponse,

    Mais si j'ai dans un même fichier (A.hpp) les prototypes et définitions (toujours séparé) d'une même classe A :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
     
    #ifndef FILE__A
    #define FILE__A
     
    class A
    {
    	public:
    		A();
    		bool uu()
    		inline int tt();
    		template<typename T> T ch(T h = 0);
     
    	protected:
    		bool u;
    		int t;
    		int c;
     
    };
     
    A::A() : u(true), t(8), c(1)
    {
     
    }
     
    bool A::uu()
    {
    	return u;
    }
     
    inline int A::tt()
    {
    	return t;
    }
     
    template<typename T> T A::ch(T h)
    {
    	if(h == 1) return h + c;
    }
     
    #endif //FILE__A
    Et que j'ai deux fichiers sources (.cpp) qui incluent ce même fichier. Il ne risquent pas d'avoir un problème de linker ?
    Non, il n'y a aucun risque...

    Pour la fonction inline, comme je l'ai indiqué, le compilateur remplacera la séquence
    • push des informations sur la fonction appelante
    • exécution fonction appelée
    • pop des informations sur la fonction appelante
    par... les instructions de la fonction appelée.

    Pour les fonctions template, le compilateur doit attendre de savoir à quoi correspond T pour créer le code exécutable en prenant la bonne taille pour représenter ce T... et réagira exactement comme si la fonction avait été déclarée inline

    Et cela, il ne peut le savoir que... lors de l'appel de ch... dans la fonction qui y fait appel
    Comment faire dans ce cas "particulier" ?

    Merci encore
    Comme tu l'as fait, c'est très bien

  6. #6
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Salut,
    Le rôle d'inline est double : indiquer que le compilateur peut remplacer l'appel de la fonction directement par son code. Le second rôle est d'indiquer que les différentes définitions n'en sont qu'une (sous réserve que ce soit effectivement la même définition). Le linker ne provoque alors pas d'erreur et une seule fonction est bien générée.

  7. #7
    Membre éprouvé
    Avatar de méphistopheles
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    1 551
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 1 551
    Points : 1 218
    Points
    1 218
    Par défaut
    Citation Envoyé par Abdelite Voir le message
    Merci pour vos réponse,

    Mais si j'ai dans un même fichier (A.hpp) les prototypes et définitions (toujours séparé) d'une même classe A :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
     
    #ifndef FILE__A
    #define FILE__A
     
    class A
    {
    	public:
    		A();
    		bool uu()
    		inline int tt();
    		template<typename T> T ch(T h = 0);
     
    	protected:
    		bool u;
    		int t;
    		int c;
     
    };
     
    A::A() : u(true), t(8), c(1)
    {
     
    }
     
    bool A::uu()
    {
    	return u;
    }
     
    inline int A::tt()
    {
    	return t;
    }
     
    template<typename T> T A::ch(T h)
    {
    	if(h == 1) return h + c;
    }
     
    #endif //FILE__A
    Et que j'ai deux fichiers sources (.cpp) qui incluent ce même fichier. Il ne risquent pas d'avoir un problème de linker ? Comment faire dans ce cas "particulier" ?

    Merci encore
    En théorie il faudrait définir A() et uu() dans un fichier séparé.

    Par contre, ta fonction inline sera effectivement redéfinie puisqu'elle sera recopiée à chaque occurrence de son appel, mais c'est effectivement ce qu'on attend d'une fonction inline.

    Pour ta fonction Template, Il me semble que le compilateur créera une nouvelle fonction pour chaque jeu de paramètre template différent avec lesquels elle sera appelé, ce qui revien à créer un .cpp a elle ne sera pas définie tant qu'elle n'est pas appvec cette fonction, pour chaque jeu paramètres templates différents avec lesquels tu l'utilise, donc pas de souci

    Bonne continuation

    edit : arf grilled. Par contre, pour les deux non template, ne serait-ce pas mieux de les définir dans un fichier séparé (ou alors le compilo s'en charge ?).

  8. #8
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 630
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 630
    Points : 30 699
    Points
    30 699
    Par défaut
    Citation Envoyé par 3DArchi Voir le message
    Salut,
    Le rôle d'inline est double : indiquer que le compilateur peut remplacer l'appel de la fonction directement par son code. Le second rôle est d'indiquer que les différentes définitions n'en sont qu'une (sous réserve que ce soit effectivement la même définition). Le linker ne provoque alors pas d'erreur et une seule fonction est bien générée.
    Oui, effectivement, tu complète ma réponse en prenant en compte le fait que le fait de déclarer une fonction inline ne fait que demander au compilateur de l'inliner...

    Mais cette nuance est surtout importante lorsque l'on parle de performances que l'on croit parfois à tord être supérieure pour les fonctions inline

  9. #9
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 630
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 630
    Points : 30 699
    Points
    30 699
    Par défaut
    Citation Envoyé par méphistopheles Voir le message
    En théorie il faudrait définir A() et uu() dans un fichier séparé.
    Oui, évidemment... Au temps pour moi... Je m'étais honteusement laissé aveugler par ch et tt

    A() et uu() poseront problème parce que ce ne sont pas des fonctions inline ni considérées comme, et ton éditeur de liens ne se plaindra pas pour ch et tt, mais bien pour A et uu...

    Si tu veux vraiment mettre ces deux fonctions particulières dans ton fichier d'en-tête, tu devra les définir au sein même de la définition de ta classe...

    Elles seront alors implicitement réputées inline

  10. #10
    Invité
    Invité(e)
    Par défaut
    Merci pour vos réponse, pour ceux à qui ça intéresse, sachez que j'ai posté ce topic, en rapport avec ce topic là : http://www.developpez.net/forums/d88...ement-sources/

    Merci encore à vous

  11. #11
    Membre éprouvé
    Avatar de méphistopheles
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    1 551
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 1 551
    Points : 1 218
    Points
    1 218
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Oui, évidemment... Au temps pour moi... Je m'étais honteusement laissé aveugler par ch et tt

    A() et uu() poseront problème parce que ce ne sont pas des fonctions inline ni considérées comme, et ton éditeur de liens ne se plaindra pas pour ch et tt, mais bien pour A et uu...

    Si tu veux vraiment mettre ces deux fonctions particulières dans ton fichier d'en-tête, tu devra les définir au sein même de la définition de ta classe...

    Elles seront alors implicitement réputées inline
    Je me disais aussi ...

  12. #12
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Si tu veux vraiment mettre ces deux fonctions particulières dans ton fichier d'en-tête, tu devra les définir au sein même de la définition de ta classe...
    Ou les définir inline comme la fonction générique.

  13. #13
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par 3DArchi Voir le message
    Ou les définir inline comme la fonction générique.
    Un constructeur et une méthode classique inline ? Attendez, repartons de 0, une fonction inline, ça sert bien a gagner en souplesse, je suis embrouillé :'(

  14. #14
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Citation Envoyé par Abdelite Voir le message
    Un constructeur et une méthode classique inline ? Attendez, repartons de 0, une fonction inline, ça sert bien a gagner en souplesse, je suis embrouillé :'(
    inline a 2 objectifs :
    1/ indiquer que le compilateur peut remplacer l'appel d'une fonction par son implémentation. Pourquoi ne pourrait-il pas le faire pour un constructeur, un destructeur ou toute autre fonction non générique ? (les seuls cas plus subtils (encore que), sont les fonctions virtuelles nécessitant le type dynamique pour résoudre l'appel).
    2/ indiquer que si différentes unités de compilation ont la même définition, alors il faut la considérer comme unique et non pas comme des définitions différentes. En quoi est-ce incompatible avec un constructeur, un destructeur ou toute autre fonction non générique (et même virtuelle, rares cas où virtuel et inline peuvent avoir un sens).

  15. #15
    Invité
    Invité(e)
    Par défaut
    Et dans mon cas (cf. lien ci-dessus), ce serait, le deuxième objectif :

    indiquer que si différentes unités de compilation ont la même définition, alors il faut la considérer comme unique et non pas comme des définitions différentes. En quoi est-ce incompatible avec un constructeur, un destructeur ou toute autre fonction non générique (et même virtuelle, rares cas où virtuel et inline peuvent avoir un sens).
    Et le premier alors ? Il est aussi remplit... l'appel de mon constructeur va être remplacé par son implémentation, et si j'ai 40 000 fonctions, 4000 constructeur, tous inline ? C'est mon exécutable qui va souffrir...

    Il n'y a pas un moyen de contourner cette règle des fonction inline et de remplir que le deuxième objectif cité ?

  16. #16
    Membre éprouvé
    Avatar de méphistopheles
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    1 551
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 1 551
    Points : 1 218
    Points
    1 218
    Par défaut
    Citation Envoyé par Abdelite Voir le message
    Il n'y a pas un moyen de contourner cette règle des fonction inline et de remplir que le deuxième objectif cité ?
    Ben si, il faut mettre les fonctions non-inline dans un .cpp...

  17. #17
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Citation Envoyé par Abdelite Voir le message
    Et dans mon cas (cf. lien ci-dessus), ce serait, le deuxième objectif :
    Oui.
    Citation Envoyé par Abdelite Voir le message
    Et le premier alors ? Il est aussi remplit... l'appel de mon constructeur va être remplacé par son implémentation, et si j'ai 40 000 fonctions, 4000 constructeur, tous inline ? C'est mon exécutable qui va souffrir...
    inline dans le premier objectif n'est qu'une indication. Le compilateur peut royalement l'ignorer et ne pas la prendre en compte. Mais, cf ci-dessous.
    Citation Envoyé par Abdelite Voir le message
    Il n'y a pas un moyen de contourner cette règle des fonction inline et de remplir que le deuxième objectif cité ?
    Peut être. En fonction du compilateur. Certains compilateurs proposent des options de compilation permettant de mieux 'tuner' les fonctions qui sont effectivement inlinées (disons que ce mot horrible veut dire que la définition remplace l'appel) ou pas.
    Par exemple, sous visual, dans les options de compilations C/C++ - Optimisation, à la ligne Expansion des fonctions inline, tu peux préciser /Ob{0|1|2} :
    Citation Envoyé par MSDN
    0 Disables inline expansion, which is on by default.
    1 Expands only functions marked as inline, __inline, __forceinline or __inline or, in a C++ member function, defined within a class declaration.
    2 Expands functions marked as inline or __inline and any other function that the compiler chooses (expansion occurs at the compiler's discretion, often referred to as auto-inlining).
    Idem sous gcc : tu as des options pour contrôler tout ça.

  18. #18
    Invité
    Invité(e)
    Par défaut
    D'accord, ce fichiers .cpp, devra donc inclure ce fichier .hpp avec la définitions des inlines, templates etc...

    Ça revient donc à la même chose que si on mettait les fonctions non-inline à la fin du .hpp non ?

    PS : J'utilise MinGW.
    Dernière modification par Invité ; 01/03/2010 à 16h54.

  19. #19
    Invité
    Invité(e)
    Par défaut
    Tient c'est bizare, je remarque que le mot clé inline peut juste être mis dans l'implémentation et pas dans la définition...

  20. #20
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 630
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 630
    Points : 30 699
    Points
    30 699
    Par défaut
    Citation Envoyé par Abdelite Voir le message
    D'accord, ce fichiers .cpp, devra donc inclure ce fichier .hpp avec la définitions des inlines, templates etc...
    [EDIT]le fichier .cpp devra disposer, quelle qu'en soit l'origine, du code correspondant à tout fonction inline ou template à laquelle il fait appel

    Cela peut soit être parce que les fonctions sont définie implicitement inline (dans la définition de la classe), soit parce qu'elles sont définie explicitement inline et en dehors de leurs classes, soit encore grace à l'inclusion du fichier dans lequel elles sont définies
    [/EDIT]
    Ça revient donc à la même chose que si on mettait les fonctions non-inline à la fin du .hpp non ?
    Non...

    Parce qu'il y a de grandes chances pour qu'un fichier d'en-tête soit inclus dans de nombreux fichiers d'implémentations, et parfois même plusieurs fois...

    Imagine simplement une fonction foo qui se trouve dans A.h

    A. h est inclu par B.h et par C.h

    Si tu dois, pour les besoin de la cause, inclure B.h et C.h dans un fichier D.cpp, A.h est inclus dans D.cpp d'une part à cause de l'inclusion de B.h et, d'autre part, à cause de l'inclusion de C.h.

    Dans ce cas, tu ne peut éviter le premier écueil qui est d'avoir deux fois la fonction implémentée dans D.cpp que grâce aux gardes anti inclusion (ifndef A_H ... define A_H ... endif), mais, jusque là, foo peut effectivement n'être implémenté qu'une fois, et l'éditeur de liens peut s'en sortir sans *trop* raler.

    Mais si, à coté de D.cpp, tu crées un fichier E.cpp qui inclut le fichier A.h, les gardes anti inclusions multiples n'agissent plus, parce que le compilateur "oublie" tous les symboles qu'il peut avoir créés pour un fichier une fois qu'il a fini de le traiter.

    Quand il arrivera à la définition de foo, il créera, pour E.cpp... le code correspondant à foo... Et il ne se plaindra même pas outre mesure...

    Par contre, quand l'éditeur de liens (ld, dans ton cas) va passer par là pour relier E.o et D.o (et tous les autres), il va... trouver une implémentation de foo dans E.o et... dans D.o... et il ne saura pas à quelle "version" de foo il doit faire correspondre les appels qu'il rencontre, parce que la règle de la définition unique aura été bafouée.

    Le résutat, c'est qu'il sortira sur une erreur en te traitant de tous les noms et... sans avoir créé ton exécutable

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. Réponses: 3
    Dernier message: 08/12/2014, 15h08
  2. Réponses: 6
    Dernier message: 18/02/2013, 17h52
  3. Réponses: 3
    Dernier message: 16/08/2009, 10h29
  4. Séparer la définition et la déclaration d'une classe
    Par prgasp77 dans le forum Langage
    Réponses: 5
    Dernier message: 24/08/2005, 22h37
  5. Définition de "Métalangage"
    Par No dans le forum Langages de programmation
    Réponses: 5
    Dernier message: 19/07/2002, 15h05

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo