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

Langage C++ Discussion :

Champ d'une structure comme paramètre d'une fonction d'une classe ?


Sujet :

Langage C++

  1. #1
    Membre régulier
    Profil pro
    Responsable d'un système d'information métier
    Inscrit en
    Janvier 2011
    Messages
    114
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Responsable d'un système d'information métier
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Janvier 2011
    Messages : 114
    Points : 113
    Points
    113
    Par défaut Champ d'une structure comme paramètre d'une fonction d'une classe ?
    Bonjour,

    Je ne trouve pas de solution à un problème qui n'en a peut-être pas... Un exemple vaudra mieux qu'une longue explication :

    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
    struct MaStructure
    {
        static double champ_1;
        static double champ_2;
        static double champ_3;
     
    };
     
    class MaClasse
    {
        map<int, MaStructure> conteneur;
     
    public :
        vector<double> MaFonction(double MaStructure:: *arg)    
    }
     
    vector<double> MaClasse::MaFonction(double MaStructure:: *arg)
    {
        vector<double> monVector;
     
        for (map<int, MaStructure>::iterator it = conteneur.begin(); it != conteneur.end(); ++it)
             monVector.push_back(it.value().*arg);
     
        return monVector;
    }
    Et si ce type de manip est possible (?), je sèche sur l'argument à l'appel de cette fonction :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
        MaClasse *classe = new Classe();
        classe->MaFonction(????);  // rien ne fonctionne
    Si je ne trouve pas de solution, il faudra que je décline MaFonction autant de fois qu'il y a de membres à MaStructure, en remplaçant chaque fois it.value().*arg par it.value().champ_1, it.value().champ_2, etc..., ce qui ne me semble pas une bonne pratique.

    J'avoue que je n'ai rien trouvé dans les forums anglo-saxons qui parle de ça, ni de près, ni de loin...

    Bonne fin de journée à tous

  2. #2
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 967
    Points
    32 967
    Billets dans le blog
    4
    Par défaut
    Je vois pas bien quel noeud au cerveau tu te fais ni pour quoi ?
    Tu veux passer un double* en paramètre ?
    Ben passe un double*... que la variable source soit static d'une classe, allouée sur la pile ou le tas, on s'en moque royalement.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  3. #3
    Membre régulier
    Profil pro
    Responsable d'un système d'information métier
    Inscrit en
    Janvier 2011
    Messages
    114
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Responsable d'un système d'information métier
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Janvier 2011
    Messages : 114
    Points : 113
    Points
    113
    Par défaut
    Merci pour ce retour, je pense que je me suis mal exprimé : je voudrais arriver à appeler (sans y parvenir pour l'instant )

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    vector<double> v1 = classe->MaFonction(MaStructure::champ_1);
    vector<double> v2 = classe->MaFonction(MaStructure::champ_2);
    vector<double> v3 = classe->MaFonction(MaStructure::champ_3);
    Plutôt que d'implémenter 3 fonctions de type :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    vector<double> MaClasse::MaFonction_1(void)
    {
        vector<double> monVector;
     
        for (map<int, MaStructure>::iterator it = conteneur.begin(); it != conteneur.end(); ++it)
             monVector.push_back(it.value().champ_1);  // une autre fonction avec champ_2, une troisième avec champ_3, ...
     
        return monVector;
    }
     
    MaClasse *classe = new Classe();
    vector<double> v1 =  classe->MaFonction_1();
    Parce que dans ce dernier cas, si je change l'algorithme dans MaFonction, je devrai répéter 3 fois la manip, avec les risques d'oublis et d'erreurs...

  4. #4
    Invité
    Invité(e)
    Par défaut
    Bonsoir,

    Étant donné que ces champs sont statics, simplement double *, voire par valeur double selon les appels dans ton dernier message.

    Par contre, vu comment tu tentes de les utiliser au sein de la boucle, j'ai quelques doutes quand à ta compréhension du mot-clé static.
    En effet, quelque soit l'objet MaStructure parcouru avec it.value() it->second, la valeur de ce champ sera exactement la même.
    Cf. Quelle est la particularité d'une fonction membre static ?

    Quand à un champ non-statique, le type double MaStructure:: *arg est tout à fait correct, et l'accès se ferait avec monVector.push_back(it->second.*arg);, en passant &MaStructure::champ_1 à ta fonction.
    Dernière modification par Invité ; 19/10/2020 à 23h09.

  5. #5
    Expert éminent sénior
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 630
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 630
    Points : 10 556
    Points
    10 556
    Par défaut
    Je pense que ce que tu veux coder n'est pas possible "simplement"

    Tu ne peux pas dire à 1 fonction de prendre tel ou tel membre juste avec le décalage (<- adresse d'1 membre = adresse de la structure + le décalage).
    J'ai 1 trou de mémoire , mais je pense qu'il existe 1 moyen "plus langage C" ... mais la portabilité va sûrement se prendre 1 tarte

    Édit : (voir le lien dans le message de @Winjerome et c'est la solution de @dasycarpum) en C++, on peut prendre l'adresse d'1 membre et l'utiliser [quasi] comme 1 pointeur.

    Il faut passer 1 valeur énumérée (donc 1 par membre, + les valeurs défaut/ sentinelle/ compteur/ ... si nécessaire) et c'est à ta fonction de prendre le bon membre (avec l'opérateur . ou ->) (<- avec 1 bon switch des familles)

    Sinon tu as la solution de bourrin
    Tu supprimes ta structure et tu fais autant de tableau que de membres

  6. #6
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 967
    Points
    32 967
    Billets dans le blog
    4
    Par défaut
    Voyons si je comprends parce que tu es très loin d'être clair...
    Tu veux une fonction qui retourne la valeur d'un champ pour toutes les instances disponibles dans la map conteneur ?
    Y'a p-e une solution template, sinon très simplement en ajoutant un simple foncteur à la fonction qui extrait ça.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  7. #7
    Membre régulier
    Profil pro
    Responsable d'un système d'information métier
    Inscrit en
    Janvier 2011
    Messages
    114
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Responsable d'un système d'information métier
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Janvier 2011
    Messages : 114
    Points : 113
    Points
    113
    Par défaut
    Citation Envoyé par Winjerome Voir le message
    Quand à un champ non-statique, le type double MaStructure:: *arg est tout à fait correct, et l'accès se ferait avec monVector.push_back(it->second.*arg);, en passant &MaStructure::champ_1 à ta fonction.
    Bon, je n'y croyais pas trop quand j'ai posté, mais ça marche ! petit récap ci-dessous :

    .h
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    struct MaStructure
    {
        double champ_1;
        double champ_2;
        double champ_3;
    };
     
    class MaClasse
    {
        map<int, MaStructure> conteneur;
     public :
        vector<double> MaFonction(double MaStructure::*arg)    
    }
    .cpp
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    vector<double> MaClasse::MaFonction(double MaStructure:: *arg)
    {
        vector<double> monVector;
     
        for (map<int, MaStructure>::iterator it = conteneur.begin(); it != conteneur.end(); ++it)
             monVector.push_back(it.value().*arg);
     
        return monVector;
    }
     
    MaClasse *classe = new MaClasse();
    vector<double> v1 = classe->MaFonction(&MaStructure::champ_1);
    vector<double> v2 = classe->MaFonction(&MaStructure::champ_2);
    vector<double> v3 = classe->MaFonction(&MaStructure::champ_3);
    Merci à tous pour vos contributions, je trouve cette solution vraiment très élégante

  8. #8
    Expert éminent sénior
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 630
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 630
    Points : 10 556
    Points
    10 556
    Par défaut
    Citation Envoyé par dasycarpum Voir le message
    je trouve cette solution vraiment très élégante
    Dommage pour toi

    Le premier point, c'est de mettre des parenthèses parce que tu peux avoir des surprises à cause de la précédence des opérateurs : &(MaStructure::champ_3).

    Et deuxième point, ta solution semble fonctionner, mais tu as 1 macro C/ C++ officielle qui fait la même chose offsetof (<- lien cppreference.com en anglais)
    Mais cette macro semble poser des problèmes avec des déférencements NULL et des comportements indéfinis.

    Apparemment son utilisation semble être (avec 1 structure A ayant 1 membre c)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
        static constexpr auto offset_c = offsetof(A, c);
        auto* a_storage = static_cast<char *>(a);
        auto* c = reinterpret_cast<int *>(a_storage + offset_c));
    Donc partir sur cette solution semble être vaseux

    Ma solution "avec des valeurs énumérées" ou celle de @Bousk "avec des pointeurs de fonctions/ foncteurs", même si on va avoir 1 "collection" à maintenir, ce sont des solutions éprouvées et qui ne dépendent pas de la magie du compilateur.

    Édit : Pour répondre à @Winjerome, VDD voisin du dessous, effectivement je [ne connaissais pas le]/ [ne me souvenais pas du] "pointeur sur membre" ... peut-être parce que je n'en ai jamais eu besoin.
    Mais lorsque je parle de magie, c'est pour prendre et utiliser le décalage (adresse de la structure + décalage = adresse du membre) et notamment la macro offsetof qui pose débat.
    D'après ton lien officiel, tout semble normaliser ... donc effectivement 1 peu d'emballement de ma part

  9. #9
    Invité
    Invité(e)
    Par défaut
    D'où un pointeur sur une variable membre relèverait de la magie ?

    Citation Envoyé par foetus Voir le message
    Le premier point, c'est de mettre des parenthèses parce que tu peux avoir des surprises à cause de la précédence des opérateurs : &(MaStructure::champ_3).
    Pourquoi pas, mais hormis alourdir l'écriture, ça ne change rien ici.

    Plus dans l'air du temps, on pourrait utiliser une lambda qui permettra d'accéder à n'importe quand champ, appeler une fonction membre, etc. (étant donné le it.value(), je présume qu'il est ici question d'une QMap et simplifie la boucle en conséquence) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    template <typename F>
    vector<double> MaClasse::MaFonction(F f)
    {
        vector<double> monVector;
        monVector.reserve( conteneur.size() ); // histoire d'éviter des réallocations inutiles
     
        for (MaStructure const & value : conteneur)
             monVector.push_back( f(value) );
     
        return monVector;
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    vector<double> v1 = classe->MaFonction([](MaStructure const & value) { return value.champ_1; });

  10. #10
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 967
    Points
    32 967
    Billets dans le blog
    4
    Par défaut
    Oui mais dans le post initial les membres sont static.
    Donc prendre un pointeur vers un static... ben c'est un simple pointeur.
    Ou alors on a encore qu'une partie du code et du problème.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  11. #11
    Expert éminent
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Décembre 2015
    Messages
    1 565
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Décembre 2015
    Messages : 1 565
    Points : 7 648
    Points
    7 648
    Par défaut
    Citation Envoyé par foetus Voir le message
    Le premier point, c'est de mettre des parenthèses parce que tu peux avoir des surprises à cause de la précédence des opérateurs : &(MaStructure::champ_3).
    Non, il n'y a pas de problème, d'ailleurs :: n'est pas un opérateur c'est un liant d'un nom. Il n'y a aucun risque
    Citation Envoyé par foetus Voir le message
    Et deuxième point, ta solution semble fonctionner, mais tu as 1 macro C/ C++ officielle qui fait la même chose
    Non plus. Cette macro ne fonctionne pas dans le cas d'héritages complexes, alors que ce qu'a utilisé nono est garanti de fonctionner même en cas de multi-héritages multiples et même virtuels. Un pointeur membre c'est fait pour ça. Et le pointeur membre n'est pas un pointeur, il n'est pas un simple nombre et peut être une structure complexe.
    Citation Envoyé par foetus Voir le message
    Mais cette macro semble poser des problèmes avec des déférencements NULL et des comportements indéfinis.
    Et oui NULL c'est 0 et ça peut être confondu avec l'offet du 1er champ. Là encore le pointeur membre distingue null qui est forcément garanti comme distinct de toute valeur valide.
    Citation Envoyé par foetus Voir le message
    Édit : Pour répondre à @Winjerome, VDD voisin du dessous, effectivement je [ne connaissais pas le]/ [ne me souvenais pas du] "pointeur sur membre" ... peut-être parce que je n'en ai jamais eu besoin.
    Mais lorsque je parle de magie, c'est pour prendre et utiliser le décalage (adresse de la structure + décalage = adresse du membre) et notamment la macro offsetof qui pose débat.
    D'après ton lien officiel, tout semble normaliser ... donc effectivement 1 peu d'emballement de ma part
    En effet, là d'accord, il ne faut surtout pas essayer de jouer avec les décalages.

    @dasycarpum, ta solution est donc bien correcte.
    Depuis le C++11, on pourrait préférer une solution consistant à transmettre un moyen d'accéder au champ (par exemple une lambda) et on aurait un système capable de gérer des cas d'accès à des données autres que des membres, mais encore une fois ta solution est valide.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 3
    Dernier message: 04/01/2009, 18h24
  2. [C#] Convertir le champ d'une classe en string
    Par Marsupilami_00 dans le forum C#
    Réponses: 9
    Dernier message: 28/08/2008, 18h39
  3. [noob] sauvegardes des champs d'une classe
    Par AlienQueen dans le forum Hibernate
    Réponses: 2
    Dernier message: 21/11/2006, 02h05
  4. Récupérer les champs d'une classe
    Par gudul dans le forum Delphi
    Réponses: 3
    Dernier message: 15/10/2006, 14h01
  5. instanciation unique d'un champs dans une classe
    Par F.Victoire dans le forum Delphi
    Réponses: 4
    Dernier message: 15/06/2006, 18h34

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