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 :

Rajouter des unités à une classe


Sujet :

C++

  1. #1
    Membre actif

    Profil pro
    Inscrit en
    Avril 2010
    Messages
    356
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 356
    Points : 206
    Points
    206
    Par défaut Rajouter des unités à une classe
    Bonjour à tous,

    Je souhaite rajouter des unités à une classe, cependant, je ne vois toujours pas comment le faire sans impacter les performances/maintenabilité du code. Imaginons que j'ai une classe comme ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    struct MaClasse
    {
        MaClasse f(const MaClasse&);
    };
    Et que je vais lui donner une unité (un booléen qui me dit si je suis dans le monde réel ou sur l'écran par exemple). Le plus simple serait de faire cela (c'est ce que j'ai trouvé sur internet notamment).

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    template<bool WorldView>
    struct MaClasse
    {
        MaClasse f(const MaClasse&);
    };
    Le problème avec ce code, c'est que si "f" est grosse, le compilateur ne va pas l'inliner et va générer deux instances de f (dommage, puisque f est strictement identique dans les deux cas). De plus, ça m'oblige à mettre la définition de f en dehors d'un .cpp.

    Une autre solution que j'ai envisagé est :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    struct MaClasseBase
    {
        MaClasseBase f(const MaClasseBase& );
    };
     
    template<bool WorldView>
    struct MaClasse : private MaClasseBase
    {
     
        inline MaClasse f(const MaClasse& c){return MaClasseBase::f(c);}
        private :
            MaClasse(const MaClasseBase& n) : MaClasse(n){}
    };
    La, on résout les deux problèmes normalement. Le problème, c'est que j'ai du code qui ne sert à rien... ce qui rend le tout plus contraignant à maintenir si MaClasseBase change.

    Avez-vous une idée pour résoudre ce problème (j'ai aussi pensé au CRTP, mais le problème, c'est que la classe de base devient template, donc ça n'apporte rien) ?

    Merci pour votre aide

    PS : J'ai le même problème avec une classe B qui souhaite étendre A mais en faisant que les fonctions qui renvoient des A renvoient des B. Utiliser le CRTP pour résoudre le problème pose les mêmes problèmes que la première solution il me semble. Si jamais cette question n'est pas naturellement résolue par la question d'au dessus, j'ouvrirai un nouveau thread.

  2. #2
    Expert éminent sénior
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 071
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Val de Marne (Île de France)

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

    Informations forums :
    Inscription : Février 2005
    Messages : 5 071
    Points : 12 116
    Points
    12 116
    Par défaut
    Vous parlez d'une solution qui ne marche pas mais vous êtes vraiment très peu loquace sur la problématique initiale.

    Je suppute d'autres solutions comme des builders, des factory ou des stratégies, mais faut avoir plus de détail sur la fonctionnalité à implémenter.

  3. #3
    Membre actif

    Profil pro
    Inscrit en
    Avril 2010
    Messages
    356
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 356
    Points : 206
    Points
    206
    Par défaut
    Globalement, je souhaiterai une vérification à la compilation que je ne fais pas n'importe quoi. L'exemple le plus simple est probablement si MaClasse est une classe de Point par exemple et le bool WorldView dit si je suis sur les coordonnées de l'écran ou sur les coordonnées du monde OpenGL par exemple.

    Dans mon cas précis, il s'agit de notes de musique et il s'agit de savoir s'il s'agit d'une note transposée ou non. En gros, on reçoit une partition, mais pour l'analyser on "normalise" la partition en clé de Do. Il s'agit de rajouter une information à la compilation qui me dit si ma note est une note normalisée (=transposée), comme ça je ne peux pas faire d'erreurs et oublier de normaliser/dénormaliser une note ou travailler sur une note dénormalisée quand j'en veux une normalisée ou vice-versa.

  4. #4
    Expert confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2012
    Messages
    1 711
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2012
    Messages : 1 711
    Points : 4 442
    Points
    4 442
    Par défaut
    Citation Envoyé par NoIdea Voir le message
    Dans mon cas précis, il s'agit de notes de musique et il s'agit de savoir s'il s'agit d'une note transposée ou non.
    La vraie question est : "y à-t-il un problème de performance ? Si oui, est-ce prouvé qu'il vient de cette fonction f non inlinée ?".

    Au passage, même si une partie du code est commun il est probable que MaClasse<true>::f() et MaClasse<false>::f() soient différentes
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    template <bool B>
    struct Foo {
       void f() {
          if(B) {
             std::cout << "foo";
          }
          else {
             std::cout << "bar";
          }
       }
    };
    Le compilo est parfaitement en droit de virer le if et de réécrire ça comme ça
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    void Foo<true>::f() {
       std::cout << "foo";
    }
     
    void Foo<false>::f() {
       std::cout << "bar";
    }
    Au final les 2 fonctions n'ont rien en commun (oui une spécialisation de template est préférable dans ce cas).

  5. #5
    Membre expert
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2011
    Messages
    739
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2011
    Messages : 739
    Points : 3 627
    Points
    3 627
    Par défaut
    Si les comportements sont identiques, un proxy en sur-couche fait-il l'affaire ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    struct S { void foo(); };
     
    template<bool> struct proxy {
      void foo() { x.foo(); }
    private:
      S x;
    };
     
    using stable = proxy<true>;
    using unstable = proxy<false>;
    Seul le proxy est dans un header (pour ce qu'il fait...) le reste peut être séparé dans des .cpp.

    Une chose, les templates n'empêche pas la séparation .h/.cpp. Si les types possibles associés à une template sont connus, il est possible de les déclarer explicitement pour mettre les définitions dans des .cpp.

  6. #6
    Membre actif

    Profil pro
    Inscrit en
    Avril 2010
    Messages
    356
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 356
    Points : 206
    Points
    206
    Par défaut
    La vraie question est : "y à-t-il un problème de performance ? Si oui, est-ce prouvé qu'il vient de cette fonction f non inlinée ?".
    La vérité c'est que je n'en sais rien, mais vu que presque toutes mes classes de musique vont être touchée (Pitch, Note, Melody, ...) puisqu'elles ont un sens à la fois dans le monde transposé (monde de l'analyse) et dans le monde "réel" (monde utilisateur où il écoute sa musique), et je trouverai ça dommage d'avoir toutes les fonctions dédoublées..

    Au passage, même si une partie du code est commun il est probable que MaClasse<true>::f() et MaClasse<false>::f() soient différentes
    Non justement, c'est exactement la même classe. Le bool sert juste à éviter à détecter des erreurs stupides à la compilation (un peu comme ce que permet boost.units pour les unités physique).

    Si les comportements sont identiques, un proxy en sur-couche fait-il l'affaire ?
    Si j'ai bien compris ta solution, c'est exactement la deuxième solution que je propose (dans mon premier message) ? Le seul défaut de celle-là, c'est que ça rajoute une dépendance inutile qui est potentiellement plus source d'erreur que le problème d'utiliser une Note non transposée quand celle-ci doit l'être ou vice-versa.


    L'idée, c'est juste de rajouter une information à la compilation pour détecter des erreurs difficiles à debugger à l'exécution.

    Une chose, les templates n'empêche pas la séparation .h/.cpp. Si les types possibles associés à une template sont connus, il est possible de les déclarer explicitement pour mettre les définitions dans des .cpp.
    En effet, ce problème là est un faux problème.

  7. #7
    Membre éprouvé
    Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mars 2009
    Messages
    552
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mars 2009
    Messages : 552
    Points : 1 060
    Points
    1 060
    Par défaut
    Citation Envoyé par NoIdea Voir le message
    Le seul défaut de celle-là, c'est que ça rajoute une dépendance inutile qui est potentiellement plus source d'erreur que le problème d'utiliser une Note non transposée quand celle-ci doit l'être ou vice-versa.
    Vouloir faire des contrôles à la compilation sur des données que tu connais à l'exécution (transposition & co) t'amènera un tas de problématiques d'initialisation qui seront sources d'erreur...

    En gros, on reçoit une partition, mais pour l'analyser on "normalise" la partition en clé de Do. Il s'agit de rajouter une information à la compilation qui me dit si ma note est une note normalisée (=transposée)
    On dirait que tu t'amènes un tas de problème en voulant faire porter par la note une information qui est à la base sur la partition non?

    Tu parles du cas OpenGL : Et quand tes coordonnées sont relatives à un noeud parent, tu fais quoi de ton booléen? Quand tu veux ajouter une translation, tu modifies chaque vertex puis tu te bas pour mémoriser le fait que tu as appliqué une transformation?

    Si tu ne dupliques pas l'information "transposé", que cette information est portée par la partition, je pense que tu auras moins envie de faire des contrôles à la compilation.

    Pour reprendre OpenGL, au lieu de modifier les coordonnées d'un modèle pour le translater dans le monde réel, tu appliques une translation sur le modèle complet.

  8. #8
    Membre actif

    Profil pro
    Inscrit en
    Avril 2010
    Messages
    356
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 356
    Points : 206
    Points
    206
    Par défaut
    Vouloir faire des contrôles à la compilation sur des données que tu connais à l'exécution (transposition & co) t'amènera un tas de problématiques d'initialisation qui seront sources d'erreur...
    Je veux juste vérifier que je manipule des données qui ont été transposées, sans me préoccuper de quoi vers quoi la transposition a eu lieu. Donc a priori, je peux totalement contrôler ça à la compilation non ?

    On dirait que tu t'amènes un tas de problème en voulant faire porter par la note une information qui est à la base sur la partition non?
    Oui et non, j'ai un peu simplifié la choses. C'est la partition qui devrait porter l'information, mais on découpe la partition en entité de longueurs (chaque "longueur" a un type différent). Souvent, pour chaque longueur (type), j'ai des algorithmes qui demandent à avoir les notes transposées et d'autres non.
    Pour éviter de faire des erreurs (car si on passe des longueurs non transposées, aucun bug apparait, c'est juste que le résultat n'est pas bon), j'aimerai pouvoir dire que l'algorithme prend une longueur<transposed = true> ou une longueur<transposed=false> (longueur représente ici plein de type différents). Ainsi, je ne peux pas faire une erreur.

    Pour l'instant on adopte la solution qui consiste à documenter si l'algorithme prend quelque chose de transposé ou non. Ca marche plutôt bien, mais des erreurs ont déjà été faites, donc je voulais faire vérifier cela par le compilateur (sans perte de performances et sans augmenter la quantité de code)

    Pour reprendre OpenGL, au lieu de modifier les coordonnées d'un modèle pour le translater dans le monde réel, tu appliques une translation sur le modèle complet.
    Oui, mais tu ne voudrais pas mélanger faire des opération entre tes coordonnées GUI et tes coordonnées OpenGL par exemple. Ou, je trouve l'exemple en physique plus parlant finalement, on peut imaginer que Note est un double. Eh bien c'est bien pratique que boost.units soit la pour dire que tous les doubles ne sont pas pareils...

Discussions similaires

  1. rajouter des colonnes à une table dynamique
    Par winsy dans le forum Composants
    Réponses: 2
    Dernier message: 27/10/2009, 13h52
  2. Réponses: 4
    Dernier message: 02/01/2009, 18h34
  3. comment ajouter des méthodes à une classe lors Runtime?
    Par revever dans le forum Collection et Stream
    Réponses: 2
    Dernier message: 31/03/2008, 13h53
  4. Rajouter des caractères à une chaîne
    Par kilian67 dans le forum Langage
    Réponses: 2
    Dernier message: 30/12/2007, 19h09
  5. [JSP][STRUTS] Passer des objets à une classe action
    Par maphi dans le forum Servlets/JSP
    Réponses: 2
    Dernier message: 10/08/2005, 16h55

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