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 :

structures pb d'initialisation


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    48
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2008
    Messages : 48
    Par défaut structures pb d'initialisation
    bonjour bonjour ....

    Voici donc mon probleme du jour :
    Je viens de faire une jolie structure point (genre MFC mais sans) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    struct point
    {
        int x,y;
    };
    je voudrais pouvoir faire tout comme dans MFC, initialiser un point avec :
    et pas etre obligé de faire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    POINT pt;
    pt.x = 100;
    pt.y = 100;
    mais ca marche pô !
    y a une astuce (sans MFC) ou je perd mon temps pour rien ?
    merci d'avance

  2. #2
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Salut, et bienvenue sur le forum.

    La solution est toute simple, et réside dans la base du langage.

    Elle s'appelle le "constructeur".

    Il s'agit "simplement" d'une fonction membre de la structure (car une structure en C++ ne diffère d'une classe que par l'accessibilité par défaut de son contenu) particulière en cela qu'elle ne renvoie rien (même pas void) et qu'elle porte le même nom que la structure que tu définis, et qu'elle sera automatiquement appelée lorsque tu déclarera une variable du type de ta structure

    Pour l'implémenter "correctement", l'idéal est quand même d'ajouter un concept tout à fait connexe à celui de constructeur: la liste d'initialisation.

    En effet, comme son nom l'indique, le constructeur a pour but de "construire" une variable qui soit directement utilisable, ce qui implique de... construire les variables membres de cette structure, et donc... d'appeler le constructeur de chacun des membres dont la structure est composée (et ainsi de suite).

    La liste d'initialiation consistera donc préciser explicitement pour chaque membre de la structure quel il faut appeler, en les séparant par une virgule.

    Comme le langage fournit des "pseudo constructeurs" pour les types primitifs, tu pourra traiter tes int exactement comme tout le reste

    Au final, ta structure deviendra
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    struct Point
    {
        /* le constructeur, nous lui passons un int pour x et un pour y */
        Point(int x, int y) : x(x),y(y){}
        int x;
        int y; 
    };
    et la déclaration d'une variable de type Point ressemblera à
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    void foo()
    {
        Point monPoint(10, 100);
        /*utilisation de monPoint */
    }
    Remarque que l'idéal est de toujours appeler le constructeur des membres de la structure dans l'ordre dans lequel les membres sont déclarés afin d'éviter les avertissement du compilateur qui seraient de nature à te compliquer la tache en cas de problème à la compilation

    Remarque en outre que la présence de cette fonction fait que ta structure devient type abstrait de donnée non POD (Plain Old Data : ne contenant que des données ou des structures POD), et que tu ne pourra donc plus l'utiliser tel quel en C, par exemple.

    Remarque aussi que la liste d'initialisation ne peut être utilisée que dans le cadre d'un constructeur.

    Remarque enfin que le constructeur "normal" devrait souvent être accompagné de trois autres fonctions particulières qui sont le constructeur de copie, l'opérateur d'assignation et le destructeur. Cependant, pour une structure aussi simple (n'utilisant pas de pointeurs et n'ayant pas de comportement trop particulier à mettre en oeuvre), tu peux laisser le compilateur implémenter ses propres versions par défaut de ces trois autres fonctions, car le comportement donné par le compilateur correspond (pour cette structure particulière, et ce n'est pas forcément le cas d'autres structures) à celui que tu implémenterais par toi même

    Enfin, et pour te donner les bonnes bases directement les bonnes habitudes, il ne me reste plus qu'à te rappeler que le C++ est ce que l'on appelle un langage orienté objet.

    Il y a plusieurs concepts sous-entendus par ces mots, mais l'un des principaux est celui de "l'encapsulation des données".

    Le principe de ce concept est de se dire que si on laisse un "champs de structure" disponible à l'ensemble du code, et que l'on décide - pour une raison quelconque - de modifier la manière dont ce champs est représenté en mémoire, ce sera l'intégralité du code qu'il faudra vérifier pour y apporter les changements adéquats.

    En effet, tel que tu es parti, que va-t-il, à ton avis, se passer si, un jour, tu venais à décider de modifier ta structure en
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    struct Point
    {
       int coord[2];
    };
    qui pourrait pourtant parfaitement convenir à la représentation d'un point deux dimentions

    La réponse est simple: partout ou tu accede à x ou à y, il faudra modifier l'acces en coord[0] ou en coord[1]... Et ca risque de faire beaucoup de lignes de code à vérifier.

    L'idée générale, et bien qu'elle puisse souffrir de certaines exception est donc de cacher "l'implémentation réelle" des données (la manière dont les données sont réellement représentées en mémoire et le nom qui permet d'y accéder), mais de fournir une fonction membre dont la seule modification permettra au reste du code de continuer à travailler correctement, sans nécessiter de modification.

    Au final, ta classe (car on parle plus souvent de classe que de structure en C++) ressemblerait à
    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
    class Point
    {
        public: /* ce qui suit est accessible à l'ensemble du code */
            /* le constructeur permettant d'initialiser les valeurs sur
             * l'axe des x et sur l'axe des y
             */
            Point(int x, int y):x(x), y(y){}
            /* les fonctions permettant de récupérer la valeur de x et de y
             * mais pas de les modifier
             */
            int getX() const{return x;}
            int getY() const{return y;}
            /* nous risquons de vouloir changer la position du point, trois
             * possibilités sont offertes: uniquement sur l'axe des x, uniquement
             * sur l'axe des y et les deux en meme temps
             */
            void setX(int newx){x = newx;}
            void setY(int newy){y = newy;}
            void moveTo(int newx, int newy)
            {
                x = newx;
                y = newy;
            } 
            /* accessoirement, nous pourrions vouloir vérifier si les coordonnées
             * sont valides... Par exemple, si x et y sont bien supérieures ou 
             * égales à 0
             */
            bool isValid() const{return x>=0 && y>=0;}
        private: /* ce qui suit n'est accessible que par les fonctions de
                  * la classe
                  */
            int x;
            int y;
            /* si, un jour, nous venions à modifier ces deux variables en
             * int coord[2];
             * nous n'aurions plus qu'à modifier les fonctions ci-dessus pour
             * que tout fonctionne normalement
             */
    };
    PS: pense à lire les commentaires que j'ai indiqués, il te permettront de comprendre ce qui est fait
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  3. #3
    Membre chevronné
    Avatar de Florian Goo
    Profil pro
    Inscrit en
    Septembre 2008
    Messages
    680
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Septembre 2008
    Messages : 680
    Par défaut
    Bonjour,

    Chez moi, ceci compile avec GCC :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    struct point
    {
        int x,y;
    };
     
    int main()
    {
    	point p = {0, 0};
     
    	return 0;
    }
    Attention, POINT != point.


    Citation Envoyé par Standard C++ ISO
    An aggregate is an array or a class (clause 9) with no user-declared constructors (12.1), no private or protected non-static data members (clause 11), no base classes (clause 10), and no virtual functions (10.3).
    When an aggregate is initialized the initializer can be an initializer-clause consisting of a brace-enclosed, comma-separated list of initializers for the members of the aggregate, written in increasing subscript or
    member order. If the aggregate contains subaggregates, this rule applies recursively to the members of the
    subaggregate. [Example:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
            struct A {
                       int x;
                       struct B {
                                 int i;
                                 int j;
                       } b;
            } a = { 1, { 2, 3 } };
    initializes a.x with 1, a.b.i with 2, a.b.j with 3. ]
    Cours : Initiation à CMake
    Projet : Scalpel, bibliothèque d'analyse de code source C++ (développement en cours)
    Ce message a été tapé avec un clavier en disposition bépo.

  4. #4
    Membre chevronné Avatar de jbarreau-mainson
    Profil pro
    Inscrit en
    Octobre 2007
    Messages
    446
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France

    Informations forums :
    Inscription : Octobre 2007
    Messages : 446
    Par défaut
    N'aurais pas t'on pu faire ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    struct point
    {
        int x,y;
    }p;
    Citation Envoyé par kaola01
    La solution est toute simple, et réside dans la base du langage.

    Elle s'appelle le "constructeur".
    Je ne savais pas que l'on pouvais faire un constructeur dans une structure !
    Il est vrai qu'au final une classe est plus simple.

  5. #5
    Membre chevronné
    Avatar de Florian Goo
    Profil pro
    Inscrit en
    Septembre 2008
    Messages
    680
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Septembre 2008
    Messages : 680
    Par défaut
    Citation Envoyé par jbarreau-mainson Voir le message
    Je ne savais pas que l'on pouvais faire un constructeur dans une structure !
    Il est vrai qu'au final une classe est plus simple.
    Une struct = une classe, sauf que par défaut les champs sont publics et non privés :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    struct a
    {
        int i; //public
    };
    class b
    {
        int i; //privé
    };
    Cours : Initiation à CMake
    Projet : Scalpel, bibliothèque d'analyse de code source C++ (développement en cours)
    Ce message a été tapé avec un clavier en disposition bépo.

  6. #6
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Citation Envoyé par jbarreau-mainson Voir le message
    N'aurais pas t'on pu faire ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    struct point
    {
        int x,y;
    }p;
    Si, cela revient strictement à
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    struct point
    {
        int x;
        int y;
    };
    La seule différence réside dans la lisibilité du code.

    J'ai pris l'habitude de n'écrire qu'une et une seule instruction / structure de contrôle par ligne, de manière à ne pas devoir commencer à me demander "quelle est l'instruction qui foire" quand il y en a plusieurs sur la même ligne.

    Cela permet d'avoir un code plus "aéré" et plus digeste pour la personne (peut-être toi-même six mois plus tard) qui devra essayer de le comprendre en ne le connaissant pas (ou en ayant oublié le but recherché par telle ou telle fonction).

    Cela permet en plus de ne pas risquer de zapper l'existence d'une variable quand il y en a beaucoup par exemple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    struct MaStruct
    {
        int a, b, c, d, e, f, g, h, i, j, k, l, m;
    };
    Ce n'est ici bien sûr qu'une habitude "personnelle", mais je t'encourage vivement à la prendre également. Tu remarquera d'ailleurs à la longue qu'elle est partagée par de nombreux programmeurs habitués, même si l'on rencontre encore volontiers des différences portant essentiellement sur la position des accolades et des mots clés dans les blocs, car il existe plusieurs "normes" de codage.
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  7. #7
    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
    Par défaut
    Citation Envoyé par jbarreau-mainson Voir le message
    N'aurais pas t'on pu faire ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    struct point
    {
        int x,y;
    }p;


    Je ne savais pas que l'on pouvais faire un constructeur dans une structure !
    Il est vrai qu'au final une classe est plus simple.
    On dirait des réflexes C. En C++, comme souligné par Florian struct==class (modulo que dans une structure, t'es en public par défaut)!

  8. #8
    Membre chevronné Avatar de jbarreau-mainson
    Profil pro
    Inscrit en
    Octobre 2007
    Messages
    446
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France

    Informations forums :
    Inscription : Octobre 2007
    Messages : 446
    Par défaut
    D'accord, merci pour ces conseils.

    Citation Envoyé par 3DArchi
    On dirait des réflexes C
    Je suis démasqué !
    Il est vrai que j'apprends actuellement les deux languages en meme temps ( contre mon gré ).

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

Discussions similaires

  1. Réponses: 0
    Dernier message: 28/03/2015, 09h43
  2. Réponses: 4
    Dernier message: 29/07/2010, 16h24
  3. initialiser les membres d'une structure
    Par molesqualeux dans le forum C
    Réponses: 8
    Dernier message: 02/02/2006, 19h57
  4. [structure] Initialisation nécessaire ?
    Par gangsoleil dans le forum Réseau
    Réponses: 6
    Dernier message: 07/03/2005, 19h27
  5. [Initialisation] Remplir une structure une fois
    Par Kimael dans le forum Langage
    Réponses: 14
    Dernier message: 08/06/2004, 15h33

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