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 :

Méthode d'une classe virtuelle pure appelant une méthode virtuelle pure => Warning.


Sujet :

C++

  1. #1
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 012
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 012
    Points : 23 136
    Points
    23 136
    Par défaut Méthode d'une classe virtuelle pure appelant une méthode virtuelle pure => Warning.
    Bonjour,

    J'ai une classe :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    class VirtualListener
        {
        public:
            void maFonction(void);
     
        protected :
                inline virtual void logStartServeur(void) = 0;
        };
     
    void VirtualListener::maFonction(void)
    {
             logStartServeur();
    }
    Mais le compilateur me met un joli warning :
    warning: inline function ‘virtual void LD::VirtualListener::logStartServeur()’ used but never defined
    Je ne comprend pas l'intérêt d'un tel warning.
    VirtualListener est virtuel pure, on ne peut pas créer d'instance même en la dérivant à moins de donner l'implémentation de la méthode logStartServeur.
    Comment pourrais-je supprimer ce warning ?

  2. #2
    Membre éclairé

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2007
    Messages
    373
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Santé

    Informations forums :
    Inscription : Juin 2007
    Messages : 373
    Points : 764
    Points
    764
    Par défaut
    Je ne comprend pas trop comment une méthode virtuelle pure peut être inline ? (c'est une vraie question)

    Pour une méthode virtuelle non pure, le corps peut être inliné si on appelle la méthode directement sur un objet (ni une référence ni un pointeur), mais dans tous les autre cas l'inline est impossible puisque la véritable fonction appelée est choisie au run time.

    Dans le cas d'une méthode virtuelle pure, il est impossible d'instancier un objet, et donc le seul cas d'application du caractère inline disparait.

    Qui plus est, il me semble que le mot clé inline ne fait pas vraiment partie du prototype de la méthode, dans le sens où :
    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
    class TestBase
    {
    public :
     
        virtual ~TestBase();
     
        inline virtual void foo() = 0;
    };
     
    class Test : public TestBase
    {
    public :
     
        void foo() override {}
    };
    ... compile parfaitement, alors que la méthode dérivée n'est elle même pas inline. En revanche, ce code produit le même warning que dans ton message précédent, warning qui disparait si on supprime le mot clé inline de la méthode de base.

  3. #3
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 012
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 012
    Points : 23 136
    Points
    23 136
    Par défaut
    Le mot clé "inline" n'est qu'une indication qu'on donne au compilateur.

    Ici, j'ai une classe virtuelle dont hérite deux autres classes.

    Ces classes utilisent plusieurs méthodes ne variant souvent que d'une ligne.

    La solution la plus simple est de faire une méthode virtuelle pure (ou simplement virtuelle si on veut mettre une ligne par défaut) et de faire :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    virtual void VirtualListener::maMéthode(void)
    {
             //début
             logStartServeur();
             //fin
    }
    Mais appeler une fonction reste une chose assez lourde pour finalement pas grand chose...
    Après, est-ce que le compilateur est suffisamment intelligent pour comprendre qu'il faut créer pour chaque classe fille une méthode maMéthode et mettre le contenu de logStartServeur dedans? Dans le doute...


    Une autre solution serait de définir tout ce qui est inline chez la mère et de définir une méthode virtuelle pure qu'on implémenterais chez la fille :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    void Fille::maMethode()
    {
           debut();
           //....
           fin();
    }
    Mais ceci ne me semble pas super...


    EDIT : je n'avais pas vu que tu avais été pendant que j'écrivais.
    Comme la méthode inline virtuelle est appelée au sein d'une méthode qui est elle aussi virtuelle, le compilateur sait dès la compilation quelle méthode inline utiliser.
    Par contre est-il capable de faire l'optimisation ?

  4. #4
    Membre éclairé

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2007
    Messages
    373
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Santé

    Informations forums :
    Inscription : Juin 2007
    Messages : 373
    Points : 764
    Points
    764
    Par défaut
    Citation Envoyé par Neckara Voir le message
    Après, est-ce que le compilateur est suffisamment intelligent pour comprendre qu'il faut créer pour chaque classe fille une méthode maMéthode et mettre le contenu de logStartServeur dedans?
    J'en doute fortement. Mais pour être sûr, il faut regarder le code assembleur, et ça sort un peu de mes compétences

    Citation Envoyé par Neckara Voir le message
    Une autre solution serait de définir tout ce qui est inline chez la mère et de définir une méthode virtuelle pure qu'on implémenterais chez la fille :
    Ca me semble déjà plus probable. En soit, ce n'est pas nécessairement une mauvaise idée si tu peux vraiment ranger début et fin dans deux fonctions qui aient un sens.

    Edit : je n'avais pas vu que tu n'avais pas vu que j'avais écrit pendant que tu écrivais...
    Citation Envoyé par Neckara Voir le message
    Comme la méthode inline virtuelle est appelée au sein d'une méthode qui est elle aussi virtuelle, le compilateur sait dès la compilation quelle méthode inline utiliser.
    Dans ton code original, la seconde méthode n'est pas virtuelle. Ton but n'était justement pas d'éviter à ré-écrire maFonction dans toutes les classes dérivées ?

  5. #5
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 012
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 012
    Points : 23 136
    Points
    23 136
    Par défaut
    Citation Envoyé par Kalith Voir le message
    Ca me semble déjà plus probable. En soit, ce n'est pas nécessairement une mauvaise idée si tu peux vraiment ranger début et fin dans deux fonctions qui aient un sens.
    C'est justement ça le problème il faut que ça ai un sens et ceci va me rajouter plus de méthodes inline à créer.
    J'ai peur que la classe devienne illisible avec trop de méthodes...

    EDIT : Ou alors une classe virtuelle pure pour l'interface.
    Et un ensemble de classes/namespace pour les méthodes/fonctions inlines ?
    Fin EDIT.

    Citation Envoyé par Kalith Voir le message
    Dans ton code original, la seconde méthode n'est pas virtuelle. Ton but n'était justement pas d'éviter à ré-écrire maFonction dans toutes les classes dérivées ?
    Heu... Si, je commence juste à m'embrouiller^^
    J'étais en train de me demander si appeler une méthode inline virtuelle dans un méthode virtuelle ne forcerait pas le compilateur à réécrire lui-même la méthode virtuelle pour chaque fille.
    Ce n'est pas totalement illogique et ça m'arrangerait bien

  6. #6
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 012
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 012
    Points : 23 136
    Points
    23 136
    Par défaut
    Je viens juste d'y penser, les templates réécrivent la fonction ou la classe pour chaque type pouvant être utilisé non?

    Dans ce cas là est-ce qu'on ne pourrait pas faire :
    - Une classe virtuelle pure (A) servant d'interface.
    - Une classe templaté (B) héritant de la classe A qui implémentera toutes les méthodes.
    - Une classe virtuelle pure (C) avec des méthodes virtuelles pures inlines.
    - Des classes héritant de A (D) qui contiendra l'implémentation de ces méthodes inlines.

    Ce qui donnerais :
    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
     
    class D : A
    {
             static inline void fctInline(void);
    };
     
    <typename T>
    void B<>::Methode()
    {
             //debut
            T::fctInline();
            //fin
    }
     
     
    A * a = B<D>::newB();
     
    a->Methode();

    Qu'en pensez-vous?

  7. #7
    Membre éclairé

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2007
    Messages
    373
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Santé

    Informations forums :
    Inscription : Juin 2007
    Messages : 373
    Points : 764
    Points
    764
    Par défaut
    Quelque chose dans ce goût là ?
    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
    41
    42
    43
    44
    45
    46
    47
    class BaseAbstract
    {
    protected :
     
        template<class T>
        inline void do_foo(T& obj) {
            // début
            obj.log();
            // fin
        }
     
    public :
     
        virtual ~BaseAbstract() = default;
     
        virtual void foo() = 0;
    };
     
    class DerivA : public BaseAbstract
    {
        friend class BaseAbstract;
     
        inline void log() {
            // logA
        }
     
    public :
     
        void foo() override {
            do_foo(*this); 
        }
    };
     
    class DerivB : public BaseAbstract
    {
        friend class BaseAbstract;
     
        inline void log() {
            // logB
        }
     
    public :
     
        void foo() override {
             do_foo(*this);
        }
    };

  8. #8
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 012
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 012
    Points : 23 136
    Points
    23 136
    Par défaut
    Je pense que c'est une solution qui pourrait marcher.

    Par contre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    template<class T>
        inline void do_foo(T& obj) {
            // début
            obj.log();
            // fin
        }
    Est-il réellement possible de créer un membre "templaté" sans "templater" la classe elle-même ?
    EDIT : d'après ce que je lis c'est possible, mais je me souviens avoir eu un problème en essayant il y a assez longtemps faudra que je réessaye^^
    EDIT2 : C'est peut être possible pour les méthodes mais pas pour les attributs ?

    Le mot clé inline n'est-il pas équivalant au fait de mettre à l'intérieur de la classe le code de la méthode ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    virtual ~BaseAbstract() = default;
    Que signifie le = default ? Va falloir que je fasse un peu de recherche.
    idem pour override^^
    EDIT : override n'est pas du C++ standard mais du C++/CLI non ?


    Je pensais plutôt à une solution comme ceci :
    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
    41
    42
    43
    44
    class Listener
    {
            virtual void action(void) = 0;
    }
     
    template<typename T>
    class newListener<T> : Listener
    {
             void action(void);
             static newListener *nouv(void);
    }
     
    template<>
    void newListener<T>::action()
    {
              //debut
             T::methodInline();
            //fin
    }
     
    template<>
    static newListener * newListener<T>::nouv(void)
    {
              return new newListener<T>();
    }
     
    class BaseInline
    {
            virtual methodInline();
    }
     
    class X : BaseInline
    {
           methodInline();
    }
     
    inline void BaseInline::methodInline()
    {
    }
     
     
    //utilisation :
    Listener * a = newListener<X>::nouveau();
    a->action();
    Désolé pour le code mais l'orage approche j'ai dû faire vite.

    Ta solution me semble plus propre, à voir quand l'orage sera partie

    EDIT2 : Finalement je préfère ma solution car lorsqu'on créé une nouvelle classe avec ta méthode on doit redéfinir les méthodes inlines et les méthodes appelant les méthodes qui appellent les méthodes inlines alors qu'avec ma solution, il suffit juste de définir les méthodes inlines.

  9. #9
    Membre éclairé

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2007
    Messages
    373
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Santé

    Informations forums :
    Inscription : Juin 2007
    Messages : 373
    Points : 764
    Points
    764
    Par défaut
    Citation Envoyé par Neckara Voir le message
    Est-il réellement possible de créer un membre "templaté" sans "templater" la classe elle-même ?
    Oui bien sûr ! Ça fonctionne comme une fonction template classique, sauf qu'il s'agit d'une fonction membre.

    Citation Envoyé par Neckara Voir le message
    Le mot clé inline n'est-il pas équivalant au fait de mettre à l'intérieur de la classe le code de la méthode ?
    Oui, tu as raison, c'est inutile de le préciser ici. Mais ça ne fait pas de mal, et ça montre que c'est intentionnel.

    Citation Envoyé par Neckara Voir le message
    Que signifie le = default ? Va falloir que je fasse un peu de recherche. [...] idem pour override^^
    Ce sont deux nouveaux mots clés qui ont été introduits par la nouvelle norme C++11 :
    • default dit au compilateur "génère moi la version par défaut de cette fonction membre" (voir ce lien). Ici, je créé une classe abstraite, il faut donc que le destructeur soit virtuel. J'ai choisi d'utiliser default, mais j'aurai très bien pu écrire
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      virtual ~BaseAbstract() {}
      Je pense que c'est surtout utile pour les constructeurs de copie. Dans le cas présent ce n'est pas forcément utile (plus long à écrire), mais ça fait découvrir le C++11 à ceux qui ne le connaissent pas
    • override est plus utile : il dit explicitement au compilateur "là je souhaite implémenter une méthode virtuelle de la classe de base" (voir ce lien). Si aucune méthode de la classe de base n'a la signature adéquate, le compilateur râle en disant qu'il ne trouve rien. Si on ne met pas override, ça compile, mais on ne se rend pas forcément compte qu'on a fait une erreur (typiquement, oublier un const dans la méthode dérivée).


    Edit : oui, ta version évite du code inutile. Par contre je ne saisis pas trop l'utilité de la méthode nouveau, ainsi que de la classe BaseInline.

  10. #10
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 012
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 012
    Points : 23 136
    Points
    23 136
    Par défaut
    BaseInline permet de définir la "base" des classes qui auront les méthodes inlines.
    En gros elle va définir le prototype et le nom de chacune des méthodes inlines nécessaires.

    Si la méthode manque là aussi le compilateur râlera mais ceci permet aussi de mettre ces prototypes dans la documentation.

    Pour la fonction nouveau en effet, elle n'est pas utile.
    On peut directement faire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    Listener & a = newListener<X>();
    ou
    Listener & a = *new newListener<X>();
    Dans ce cas là, je pense que renommer newListener en createListener et créer une fonction newListener<X> renvoyant un pointeur sur un createListener serait plus lisible.

  11. #11
    Membre éclairé

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2007
    Messages
    373
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Santé

    Informations forums :
    Inscription : Juin 2007
    Messages : 373
    Points : 764
    Points
    764
    Par défaut
    Citation Envoyé par Neckara Voir le message
    On peut directement faire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Listener & a = *new newListener<X>();
    Là tu as une fuite de mémoire, et dans le premier cas du assigne un temporaire à une référence non constante (ça ne compile pas).

    Sinon quelques remarques :
    • Si tu veux que BaseInline définisse l'interface que doit présenter X et les autres listeners que tu peux imaginer, alors il faut que les fonctions membres soient virtuelles (pures), donc non statiques (on ne peut pas avoir l'un et l'autre à la fois, ça n'a pas de sens). Malgré tout, il faudra bien déclarer toutes les méthodes de X comme étant inline (c'est un attribut qui ne s'hérite pas).
    • Pour éviter à l'utilisateur de voir "à l'intérieur" de cette magouille, il vaudrait mieux utiliser un typedef vers un nom sympatique.
    • On s'approche beaucoup du concept de politique, qui reviendrait ici à faire :
      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
      class Listener
      {
      public :
       
          virtual void action() = 0;
      };
       
      template<typename LogPolicy>
      class ListenerPolicies : public Listener
      {
      public :
       
          void action() {
              // début
              LogPolicy::log();
              // fin
          }
      };
       
      struct LogToDisk
      {
          inline static void log() {
              // ...
          }
      };
       
      struct LogToConsole
      {
          inline static void log() {
              // ...
          }
      };
       
      // utilisation :
      Listener* p = new ListenerPolicies<LogToDisk>();
      p->action();
      Pour savoir s'il vaut mieux s'orienter vers ce design là, il faudrait connaitre le contexte dans lequel tu cherches à faire tout ça, c'est à dire quelles sont les différences possibles entre tes classes dérivées.

  12. #12
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2012
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mai 2012
    Messages : 4
    Points : 15
    Points
    15
    Par défaut
    Bonjour,

    J'arrive un peu tard, mais je vais essayer de corriger les quelques erreurs qui ont été dites.

    Citation Envoyé par Neckara Voir le message
    J'ai une classe :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    class VirtualListener
        {
        public:
            void maFonction(void);
     
        protected :
                inline virtual void logStartServeur(void) = 0;
        };
     
    void VirtualListener::maFonction(void)
    {
             logStartServeur();
    }
    Mais le compilateur me met un joli warning :
    warning: inline function 'virtual void LD::VirtualListener::logStartServeur()' used but never defined
    inline sert à inliner le code d'une fonction. Si tu ne définis pas cette fonction, cela ne sert à rien, puisqu'il n'y a aucun code à inliner. Le fait que ton compilateur dise « used but never defined » est peut-être un bug… quoi que il n'a pas tout à fait tord puisque si tu écris inline, il est raisonable de s'attendre à ce que tu définisses la fonction, ce que tu ne fais pas.
    Juste pour information (je n'arrive pas à déterminer avec vos messages si vous le savez ou non), il est possible de définir une fonction virtuelle pure (ce qui explique le warning).

    Citation Envoyé par Neckara Voir le message
    Le mot clé "inline" n'est qu'une indication qu'on donne au compilateur.
    Citation Envoyé par n3290 7.1.1 [dcl.fct.spec] ¶2
    A function declaration (8.3.5, 9.3, 11.3) with an inline specifier declares an inline function. The inline specifier indicates to the implementation that inline substitution of the function body at the point of call is to be preferred to the usual function call mechanism. An implementation is not required to perform this inline substitution at the point of call; however, even if this inline substitution is omitted, the other rules for inline functions defined by 7.1.2 shall still be respected.
    La mise en gras est de moi.
    En effet, ce n'est qu'une indication, mais certaines règles s'appliquent aux fonctions inlines, qu'elles soient réellement inlinées par le compilateur ou non.

    Citation Envoyé par Kalith Voir le message
    Qui plus est, il me semble que le mot clé inline ne fait pas vraiment partie du prototype de la méthode, dans le sens où :
    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
    class TestBase
    {
    public :
     
        virtual ~TestBase();
     
        inline virtual void foo() = 0;
    };
     
    class Test : public TestBase
    {
    public :
     
        void foo() override {}
    };
    ... compile parfaitement, alors que la méthode dérivée n'est elle même pas inline. En revanche, ce code produit le même warning que dans ton message précédent, warning qui disparait si on supprime le mot clé inline de la méthode de base.
    En fait, Test::foo() est inline ici aussi…
    Citation Envoyé par n3290 7.1.2 [dcl.fct.spec] ¶3
    A function defined within a class definition is an inline function. […]
    Mais oui, inline ne fait pas partie de la signature.

    Citation Envoyé par Kalith Voir le message
    • default […]
      Je pense que c'est surtout utile pour les constructeurs de copie. Dans le cas présent ce n'est pas forcément utile (plus long à écrire), mais ça fait découvrir le C++11 à ceux qui ne le connaissent pas
    En fait, c'est surtout utile quand une définition par défaut disparait quand on déclare une variante, par exemple si tu veux un constructeur par défaut ET un constructeur à deux paramètres.

    Si je comprends bien, vous utilisez des class templates et de l'héritage pour essayer d'inliner l'appel à VirtualListener::logStartServeur (et overrides) dans VirtualListener::maFonction ?
    Déjà, une fonction virtuelle et inline, j'ai le souvenir d'une implémentation que l'on pourrait appeler ainsi, c'était dans cfront (pas tout jeune donc) : au lieu de mettre un pointeur sur la fonction dans la vtable, le code de la fonction y été directement mis.
    Hormis cela, ce que tu cherches à faire est tout simplement impossible… comment le compilateur pourrait il inliner un code qu'il ne connait pas encore ? La seule manière est de redéfinir maFonction dans toutes les classes dérivées.
    Si tu veux faire ça, tu peux tout simplement utiliser un CRTP, mais c'est tordu et ça ne t'avancera à rien. Ton problème semble assez confus, mais l'idée de Kalith d'utiliser des policies est peut être ce que tu cherchais ? Par contre, c'est une solution compile-time seulement…

    Citation Envoyé par Neckara Voir le message
    Mais appeler une fonction reste une chose assez lourde pour finalement pas grand chose...
    Je ne sais pas si tu travailles pour de l'embarqué où quelque chose comme cela, mais non, un appel de fonction ne sera pas si lourd que ça, surtout que là, tu as l'air de faire de l'IO, ce qui sera certainement beaucoup plus lent.
    En plus, si le compilateur utilise le pointeur sur du code dans la vtable comme j'ai dit plus haut, ça te couteras seulement une indirection (par contre, je ne sais pas si ce genre d'optimisation est toujours d'actualité…)

  13. #13
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 012
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 012
    Points : 23 136
    Points
    23 136
    Par défaut
    Citation Envoyé par Kalith Voir le message
    Là tu as une fuite de mémoire, et dans le premier cas du assigne un temporaire à une référence non constante (ça ne compile pas).
    Une référence prend un objet pour se construire mais c'est bien l'adresse de l'objet qu'il regarde. Ce code compile bel et bien.
    Après on a pas forcément de fuites de mémoires, on peut toujours faire un delete &referance certes ce n'est pas propres mais ça fonctionne parfaitement

    Citation Envoyé par Kalith Voir le message
    • Si tu veux que BaseInline définisse l'interface que doit présenter X et les autres listeners que tu peux imaginer, alors il faut que les fonctions membres soient virtuelles (pures), donc non statiques (on ne peut pas avoir l'un et l'autre à la fois, ça n'a pas de sens). Malgré tout, il faudra bien déclarer toutes les méthodes de X comme étant inline (c'est un attribut qui ne s'hérite pas).
    • Sinon je passe par des méthodes virtuelles normales et je créé une instance lors de la construction comme ton premier exemple.

      Citation Envoyé par Kalith Voir le message
    • Pour éviter à l'utilisateur de voir "à l'intérieur" de cette magouille, il vaudrait mieux utiliser un typedef vers un nom sympatique.
    Je ne comprend pas exactement ce que tu veux faire.


    Citation Envoyé par Kalith Voir le message
    Pour savoir s'il vaut mieux s'orienter vers ce design là, il faudrait connaitre le contexte dans lequel tu cherches à faire tout ça, c'est à dire quelles sont les différences possibles entre tes classes dérivées.
  14. J'ai deux classes listener, l'une pour écouter le port admin, l'autre pour écouter celui du port client.
    Ces deux classes sont très similaires à quelques petites exceptions :
    - on a une zone critique pour le port client et on en a pas pour le port admin.
    - dans les deux cas, on va logger des messages différents ou ne pas logger.

    Ceci permettra aussi aux personnes voulant reprendre les sources d'adapter plus facilement les messages de logs.



    Citation Envoyé par ÉJLS. Voir le message
    Juste pour information (je n'arrive pas à déterminer avec vos messages si vous le savez ou non), il est possible de définir une fonction virtuelle pure (ce qui explique le warning).
    Oui en mettant = 0 pour lui dire qu'il n'existe pas d'implémentation pour cette méthode et que la classe fille, si elle ne veut pas être virtuelle pure devra implémenter cette méthode.



    Citation Envoyé par ÉJLS. Voir le message
    Si je comprends bien, vous utilisez des class templates et de l'héritage pour essayer d'inliner l'appel à VirtualListener::logStartServeur (et overrides) dans VirtualListener::maFonction ?
    Non, VirtualListener n'aura que des méthodes virtuelles pures. On essaye d'inliner l'appel de T::logStartServeur() dans ListenerFille<T>::maMethode()


    Citation Envoyé par ÉJLS. Voir le message
    Déjà, une fonction virtuelle et inline, j'ai le souvenir d'une implémentation que l'on pourrait appeler ainsi, c'était dans cfront (pas tout jeune donc) : au lieu de mettre un pointeur sur la fonction dans la vtable, le code de la fonction y été directement mis.
    J'imagine que ce n'est pas une bonne idée ?

    Citation Envoyé par ÉJLS. Voir le message
    Hormis cela, ce que tu cherches à faire est tout simplement impossible… comment le compilateur pourrait il inliner un code qu'il ne connait pas encore ?
    Si lors de la ligne d'appel le compilateur sait de façon sûre quelle méthode est appelée alors il inline.
    Comme je vais avoir T a; a.logStartServeur(); Le compilateur va écrire la classe template pour tous les types possibles donc il va inliner non?


    Citation Envoyé par ÉJLS. Voir le message
    Si tu veux faire ça, tu peux tout simplement utiliser un CRTP, mais c'est tordu et ça ne t'avancera à rien.
    Je vais me renseigner à ce sujet.

    EDIT : en gros je ferais :
    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
    template<typename T>
    class VirtualListener
    {
          public :
            void methode(void)
            {
                   //debut
                   T::monInline();
                   //fin
            }
    }
     
    class ListenerClient : VirtualListener<T>
    {
            private :
                  void monInline(void){}
    }
    Et dans ce cas là, je pourrais aussi me servir de VirtualListener pour donner les prototypes à définir dans les classes filles avec des virtuelles pures ?
    Mais pourquoi est-ce que ceci ne m'avancerait à rien ?


    Citation Envoyé par ÉJLS. Voir le message
    mais l'idée de Kalith d'utiliser des policies est peut être ce que tu cherchais ? Par contre, c'est une solution compile-time seulement…
    compile-time ? ie ?
    EDIT : oui c'est le but recherché.



    Citation Envoyé par ÉJLS. Voir le message
    Je ne sais pas si tu travailles pour de l'embarqué où quelque chose comme cela, mais non, un appel de fonction ne sera pas si lourd que ça, surtout que là, tu as l'air de faire de l'IO, ce qui sera certainement beaucoup plus lent.
    C'est un projet perso.
    Dans le cas du listener pour les admins, il va écouter un port et il va à chaque tour de boucle appeler une fonction de traitement pour traiter le paquet reçu.
    Mais dans le cas du listener pour les clients, il va lire en boucle et inscrire les paquets reçus dans une file qui sera traitée par un ensemble de thread consommateur. C'est donc une zone qui doit être traitée le plus rapidement possible. Or utiliser des fonctions non inline reviendrait à faire plus de 10 appels/retours de fonctions pour parfois une seule ligne de code.


    Bon après ça me permet aussi d'apprendre et d'approfondir mes connaissances.

  • #14
    Membre éclairé

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2007
    Messages
    373
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Santé

    Informations forums :
    Inscription : Juin 2007
    Messages : 373
    Points : 764
    Points
    764
    Par défaut
    Citation Envoyé par ÉJLS. Voir le message
    Juste pour information (je n'arrive pas à déterminer avec vos messages si vous le savez ou non), il est possible de définir une fonction virtuelle pure (ce qui explique le warning).
    J'avais oublié Effectivement, le warning prend plus de sens quand on prend ça en considération.

    Citation Envoyé par ÉJLS. Voir le message
    En fait, Test::foo() est inline ici aussi…
    Oui, ce n'est pas forcément très malin de l'avoir écrit comme ça. Je voulais éviter le code à rallonge, et préciser explicitement quelles méthodes on déclarait comme inline (étant sous entendu que, comme dans le problème initial, on ne définit aucune méthode directement dans le code de la classe).

    Citation Envoyé par ÉJLS. Voir le message
    En fait, c'est surtout utile quand une définition par défaut disparait quand on déclare une variante, par exemple si tu veux un constructeur par défaut ET un constructeur à deux paramètres.
    C'est l'une des autres utilités de ce mot clé, mais je le trouve clairement plus utile dans le cas d'un constructeur de copie, où il y a clairement beaucoup de choses à écrire si l'on veut reproduire le comportement par défaut (contrairement au constructeur par défaut et au destructeur, qui ont un corps vide).

    Citation Envoyé par Neckara Voir le message
    Une référence prend un objet pour se construire mais c'est bien l'adresse de l'objet qu'il regarde. Ce code compile bel et bien.
    Après on a pas forcément de fuites de mémoires, on peut toujours faire un delete &referance certes ce n'est pas propres mais ça fonctionne parfaitement
    Eh ben ça ne compile pas chez moi :
    error : invalid initialization of non-const reference of type 'int&' from an rvalue of type 'int'
    Et pour le second, oui tu peux faire ça mais...


    Citation Envoyé par Neckara Voir le message
    Je ne comprend pas exactement ce que tu veux faire.
    Oui je n'ai pas beaucoup développé puisque je pense qu'avec les politiques le code est beaucoup plus simple. Mais si tu veux, dans ton code j'aurai ajouté :
    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
    41
    class Listener
    {
    public :
            virtual void action() = 0;
    }
     
    template<typename T>
    class newListener<T> : Listener
    {
    public :
             void action();
    }
     
    template<typename T>
    void newListener<T>::action()
    {
             //debut
             T::methodInline();
             //fin
    }
     
    class BaseInline
    {
            virtual void methodInline() = 0;
    }
     
    class X : BaseInline
    {
           inline void methodInline();
    }
     
    inline void X::methodInline()
    {
    }
     
    // Ajouter un typedef pour clarifier les choses
    typedef newListener<X> XListener;
     
    // Utilisation (l'utilisateur ne voit pas l'étape intermédiaire avec newListener) :
    Listener * a = new XListener();
    a->action();
    Citation Envoyé par Neckara Voir le message
    J'ai deux classes listener, l'une pour écouter le port admin, l'autre pour écouter celui du port client.
    Ces deux classes sont très similaires à quelques petites exceptions :
    - on a une zone critique pour le port client et on en a pas pour le port admin.
    - dans les deux cas, on va logger des messages différents ou ne pas logger.
    D'accord, donc ça peut effectivement être intéressant d'utiliser les politiques :
    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
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    class Listener
    {
    public :
     
        virtual void action() = 0;
    };
     
    template<typename LogPolicy, typename CriticalSectionPolicy>
    class ListenerPolicies : public Listener
    {
        CriticalSectionPolicy section;
        LogPolicy             log;
     
    public :
     
        void action() {
            section.begin();
            // début
            log.print();
            // fin
            section.end();
        }
    };
     
    struct LogClientMessage
    {
        void print() {
            // ...
        }
    };
     
    struct LogAdminMessage
    {
        void print() {
            // ...
        }
    };
     
    class CriticalSectionMutex
    {
        std::mutex m;
     
    public :
     
        void begin() {
            m.lock();
        }
     
        void end() {
            m.unlock();
        }
    }
     
    struct CriticalSectionNone
    {
        void begin() {}
        void end() {}
    }
     
    // Raccourcis d'écriture :
    typedef ListenerPolicies<LogClientMessage, CriticalSectionMutex> ClientListener;
    typedef ListenerPolicies<LogAdminMessage,  CriticalSectionNone>  AdminListener;
     
    // utilisation :
    Listener* p = new ClientListener();
    p->action();
    Tout l'intérêt de ce design c'est que tu n'auras pratiquement rien à ré-écrire le jour où tu auras besoin d'un troisième listener qui aurait le même output que le listener client mais sans section critique, ou l'output admin avec une section critique, etc.

  • #15
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 012
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 012
    Points : 23 136
    Points
    23 136
    Par défaut
    Citation Envoyé par Kalith Voir le message
    Eh ben ça ne compile pas chez moi :
    Je croyais que tu parlais de la méthode avec le new. Donc j'avais raison de passer par une méthode statique.

    Citation Envoyé par Kalith Voir le message
    Et pour le second, oui tu peux faire ça mais...
    Bon c'était plus de la fainéantise qu'autre chose, autant utiliser un pointeur plutôt qu'une référence.


    Citation Envoyé par Kalith Voir le message
    Oui je n'ai pas beaucoup développé puisque je pense qu'avec les politiques le code est beaucoup plus simple. Mais si tu veux, dans ton code j'aurai ajouté :
    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
    41
    class Listener
    {
    public :
            virtual void action() = 0;
    }
     
    template<typename T>
    class newListener<T> : Listener
    {
    public :
             void action();
    }
     
    template<typename T>
    void newListener<T>::action()
    {
             //debut
             T::methodInline();
             //fin
    }
     
    class BaseInline
    {
            virtual void methodInline() = 0;
    }
     
    class X : BaseInline
    {
           inline void methodInline();
    }
     
    inline void X::methodInline()
    {
    }
     
    // Ajouter un typedef pour clarifier les choses
    typedef newListener<X> XListener;
     
    // Utilisation (l'utilisateur ne voit pas l'étape intermédiaire avec newListener) :
    Listener * a = new XListener();
    a->action();
    D'accord je comprend mieux.


    Citation Envoyé par Kalith Voir le message
    D'accord, donc ça peut effectivement être intéressant d'utiliser les politiques :
    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
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    class Listener
    {
    public :
     
        virtual void action() = 0;
    };
     
    template<typename LogPolicy, typename CriticalSectionPolicy>
    class ListenerPolicies : public Listener
    {
        CriticalSectionPolicy section;
        LogPolicy             log;
     
    public :
     
        void action() {
            section.begin();
            // début
            log.print();
            // fin
            section.end();
        }
    };
     
    struct LogClientMessage
    {
        void print() {
            // ...
        }
    };
     
    struct LogAdminMessage
    {
        void print() {
            // ...
        }
    };
     
    class CriticalSectionMutex
    {
        std::mutex m;
     
    public :
     
        void begin() {
            m.lock();
        }
     
        void end() {
            m.unlock();
        }
    }
     
    struct CriticalSectionNone
    {
        void begin() {}
        void end() {}
    }
     
    // Raccourcis d'écriture :
    typedef ListenerPolicies<LogClientMessage, CriticalSectionMutex> ClientListener;
    typedef ListenerPolicies<LogAdminMessage,  CriticalSectionNone>  AdminListener;
     
    // utilisation :
    Listener* p = new ClientListener();
    p->action();
    Tout l'intérêt de ce design c'est que tu n'auras pratiquement rien à ré-écrire le jour où tu auras besoin d'un troisième listener qui aurait le même output que le listener client mais sans section critique, ou l'output admin avec une section critique, etc.
    Très intéressant, merci beaucoup.
    Je pense que c'est la solution que je vais retenir.

    Les designs pattern sont très utiles et j'aimerais bien apprendre à utiliser d'autres designs pattern mais lorsque j'avais fait des recherches j'étais tombé sur des résultats indigestes.

    Comme avec une description du design pattern, un exemple d'implémentation mais aucun mot sur l'utilité/avantage/utilisation du design pattern
    On se retrouvait à la fin du tutoriel avec un code contenant 5-6 design pattern sans même comprendre pourquoi on les avaient utilisés...

    Est-ce que vous auriez des liens intéressants à ce sujet ?

  • #16
    gl
    gl est déconnecté
    Rédacteur

    Homme Profil pro
    Inscrit en
    Juin 2002
    Messages
    2 165
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : Juin 2002
    Messages : 2 165
    Points : 4 637
    Points
    4 637
    Par défaut
    Citation Envoyé par Neckara Voir le message
    Oui en mettant = 0 pour lui dire qu'il n'existe pas d'implémentation pour cette méthode et que la classe fille, si elle ne veut pas être virtuelle pure devra implémenter cette méthode.
    Je pense que tu n'as pas compris la remarque de ÉJLS., il signale justement qu'une méthode virtuelle pure peut avoir une implémentation.

    Citation Envoyé par Neckara Voir le message
    Non, VirtualListener n'aura que des méthodes virtuelles pures. On essaye d'inliner l'appel de T::logStartServeur() dans ListenerFille<T>::maMethode()
    Mais c'est donc T::logStartServeur() qui doit être inline, pas VirtualListener::logStartServeur().

  • + Répondre à la discussion
    Cette discussion est résolue.
    ActualitésFAQ C++Tutoriels C++Livres C++Outils & compilateurs C++Sources C++Qt

    Discussions similaires

    1. Réponses: 3
      Dernier message: 02/07/2013, 09h04
    2. Réponses: 1
      Dernier message: 23/12/2011, 17h45
    3. appeler une classe au sein d'une servlet
      Par switch1 dans le forum Hibernate
      Réponses: 10
      Dernier message: 22/05/2009, 21h11
    4. Appeler une Applet ou servlet depuis une classe java
      Par oussam dans le forum Applets
      Réponses: 2
      Dernier message: 04/07/2006, 13h58
    5. Réponses: 14
      Dernier message: 15/12/2005, 18h46

    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