Partage
  • Partager sur Facebook
  • Partager sur Twitter

Surcharger une classe avec un tableau?

Sujet résolu
    23 janvier 2019 à 15:54:45

    Coucou,

    J'aimerais créer une classe qui peut (doit en faites!) être surchargez avec un tableaux de "Tile" (Classe) de 100*100, donc multi-dimensionnel, mais voilà : peu importe ce que j'essaye de faire, le compilateur me crache dessus :/, voici TRÈS GROSSIÈREMENT ce que j'essaye de réaliser : 

    Voici le "Map.h"

    #ifndef MAP_H_INCLUDED
    #define MAP_H_INCLUDED
    #include "Tile.h"
    #include <vector>
    #include <iostream>
    #include <SFML/Graphics.hpp>
    
    class Map
    {
        //---VARIABLES---
    
        Tile tiles[100][100];
    
        //---FONCTIONS---
    
        public:
    
        Map(Tile s_tiles [100][100]);
        void resetLighting();
        void resetLighting(int x,int y);
        sf::Texture getTexture(int x,int y);
    
    
    };
    
    
    #endif // MAP_H_INCLUDED
    

    Et enfin "Map.cpp" :

    #include "Tile.h"
    
    Map(Tile s_tiles[100][100]):tiles(s_tiles)
        {
    
        }
    

    Mais le compilateur n'aime vraiment pas ça et écrit :

    "only constructors take member initializers|"

    J'ai essayé plein de "syntaxe" mais cela ne change rien, merci de votre aide à l'avance ^^

    • Partager sur Facebook
    • Partager sur Twitter
      23 janvier 2019 à 16:29:59

      "Variables", ça veut rien dire, c'est des champs de la classe.

      N'utilisez pas de tableau à la C en C++, c'est galère et c'est casse-gueule.

      Utilisez plutôt la classe std::array du C++.

      Utilisez des références pour le pas avoir des copies du contenu de ces tableaux dans tout les sens.

      Utilisez plutôt un tableau à une dimension de taille 100*100 plutôt qu'un tableau à 2 dimensions (linéarisation d'un tableau multidimensionnel).

      C'est quoi ce "s_" qui pue la notation hongroise toute moisie ?

      • Partager sur Facebook
      • Partager sur Twitter
      Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
        23 janvier 2019 à 17:15:50

        Bonjour,

        Tu devrais te faire une classe matrice en template comme celle-ci par exemple:

        template <typename T>
        class MatrixTemp2D{
        public:
            MatrixTemp2D(size_t width, size_t height):
                width_{width},
        		height_{height},
        		datas_(width*height)
        	{}
        
            T operator()(size_t x, size_t y) const{
                assert(x < width_);
                assert(y < height_);
                return datas_[y*width_ + x];
            }
            T & operator()(size_t x, size_t y) {
                assert(x < width_);
                assert(y < height_);
                return datas_[y*width_ + x];
            }
        	
        	std::size_t width() const
        	{
                return width_;
            }
            std::size_t height() const
        	{
                return height_;
            }
        	std::size_t size() const
        	{
        		return datas_.size();
        	}
        	
        private:
            std::size_t width_;
            std::size_t height_;
            std::vector<T> datas_;
        };



        -
        Edité par Warren79 23 janvier 2019 à 17:16:13

        • Partager sur Facebook
        • Partager sur Twitter

        Mon site web de jeux SDL2 entre autres : https://www.ant01.fr

          23 janvier 2019 à 17:35:13

          En ce qui concerne ma notation, c'est le "s" de "settings" juste parce que voilà...Pour un 1er programme je préfère me gérer solo, mais je sais très bien qu'un jour je changerais toute la notation. Bref! Je ne suis pas assez avancez en C++ pour connaître les template, il n'y aurais pas plus simples? Parce que je veux juste un tableaux dans une classe ^^' hein...
          • Partager sur Facebook
          • Partager sur Twitter
            23 janvier 2019 à 18:08:11

            "s_", c'est généralement un vielle notation pour des champs statiques, selon les conventions de nommage "hongroise".

            Tu peux pas le deviner, mais c'est bien de ne pas trop mélanger les notations.

            Le fait de "marquer" qu'un paramètre d'une fonction vient de "settings", c'est pas très pertinent.

            La fonction "fonctionnera" que la source des arguments soit un "settings" ou tout autre chose.

            Ne pas surcharger les notations avec des trucs inutiles.

            >mais je sais très bien qu'un jour je changerais toute la notation

            Autant prendre directement les bonnes habitudes, prend une convention de nommage C++ (attention les conventions de nommages sont spécifiques à un langage), comme celle de Google ou autre.

            Si elles existent, c'est qu'elles ont un intérêt non négligeable, comme ne pas surcharger les notations avec des trucs inutiles. ;-)

            >Je ne suis pas assez avancez en C++ pour connaître les template

            C'est pas grave. Oui, c'est un topics avancé pour en fabriquer un, mais les utiliser, c'est très simple. std::string est déjà un template mais c'est une classe "de base" du C++.

            > il n'y aurais pas plus simples?

            S'en servir, c'est largement de qu'il y a de plus simple.

            >Parce que je veux juste un tableaux

            Les tableaux C, c'est de la merde, ça oblige à utiliser des pointeurs nus tout pourri, à faire les copies "à la main", des allocations qui vont fuir, la stack qui va exploser, etc...

            En utilisant le template de Warren79, c'est nettement plus simple :

            class Map
            { 
                MatrixTemp2D<Tile> m_tiles;
             
                //---FONCTIONS---
             
                public:
             
                Map(MatrixTemp2D<Tile> tiles);
                void resetLighting();
                void resetLighting(int x,int y);
                sf::Texture getTexture(int x,int y);
            };
            
            ...
            
            Map::Map(MatrixTemp2D<Tile> tiles):m_tiles(tiles)
            {
            }
            
            void Map::resetLighting(int x,int y)
            {
               m_tiles(x,y).resetLighting();
            }
            
            sf::Texture Map::getTexture(int x,int y)
            {
               m_tiles(x,y).getTexture();
            }

            Et dans tout ce code, la copie, les allocations, les libérations, la gestion d'une taille variable de map, etc... est déjà pris en compte "gratuitement".

            Considère "MatrixTemp2D" comme ton "tableau", mais en largement mieux qu'un tableau C à 2 dimensions.

            • Partager sur Facebook
            • Partager sur Twitter
            Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
              23 janvier 2019 à 18:26:37

              Revenons sur le sujet, la question n'est pas la haine nécessaire envers les tableaux et l'adoration qu'on doit porter respectueusement aux templates - les pointeurs intelligents sont absents pour une fois - , mais une histoire d'initialisation d'une donnée membre de type "tableau".

              Simplifions : si on écrit

              class C {
              private:
              	int m_t[10];
              	public:
              	C(int t[10]) : 
                               m_t {t} // erreur compilation
                      {}
              };

              On se traine une erreur de compilation dans la liste d'initialisation parce que, en gros, on ne peut pas affecter un tableau "style C" dans un autre.  Pas possible de faire m_t = t;

              Raison : un tableau, c'est -approximativement- l'adresse d'un emplacement contenant les cases, et que affecter l'adresse, c'est pas affecter les cases.

              Mais bon, on peut faire autrement, avec une donnée membre qui est un pointeur et non un tableau

              class C {
              private:
              	int *m_t;             // changement
              public:
              	C(int t[10]);         // ok
              };

              Attention, ça ne stockera pas une _copie_ du contenu du tableau, donc il y aura des précautions à prendre sur la durée de vie des données.


              Ca va se compliquer avec un tableau 2d. On peut s'en sortir comme ça

              typedef int ligne[10];
              
              class C {
              private:
              	ligne * m_t;
              public:
              	C(ligne t[10])
              	   : m_t {t}
                 {}
              };


              ou comme ça

              typedef int mat[10][10];
              
              class C {
              private:
              	mat & m_t;
              public:
              	C(mat & t)
              	   : m_t {t}
                 {}
              };

              (manque de temps, non testé à l'exécution).

              PS:

              Enfin, ce n'est pas une bonne idée de réinventer une classe Matrice, alors qu'il suffit d'utiliser la bibliothèque standard et un brave alias.

              using Mat3x3  = std::array< std::array<float, 3> 3>;
              
              Mat3x3  m ;
              m[1,2] = 3.14;
              

              ou, pour des matrices carrées génériques

              template <typename T, int N> 
              using Mat = std::array< std::array<T, N>, N>;
              
              Mat<bool, 10>  m;
              
              m[3][8] = true;
              





              -
              Edité par michelbillaud 24 janvier 2019 à 13:42:33

              • Partager sur Facebook
              • Partager sur Twitter
                24 janvier 2019 à 19:01:28

                Salut,

                Et pour les matrices pleines mais pas forcément carrées (genre : 9 lignes de 4 colonnes), on peut utiliser un alias proche de

                template <typename T, int L, int C>
                using Mat = std::array<std::array<T, C>, L>;


                Par contre, il faudra toujours prendre en compte qu'une matrice, c'est un ensemble de Lignes * Colonnes éléments qui sont-- a priori --  contigus en mémoire, et qui nécessite donc un espace mémoire proportionnel non seulement à la taille des éléments qu'il faut représenter, mais aussi au nombre de lignes et au nombre de colonnes que l'on souhaite représenter.

                Or, un tel alias de type est tout à fait susceptible de prendre place dans la pile d'appels, qui est un espace mémoire pour le moins limité (rarement plus de 1 à 2 Mb ).  Le risque de saturer la pile en essayer d'y faire entrer plus de données que ce qu'elle n'est capable d'en contenir est donc particulièrement présent.  Et ca, ca représente une situation catastrophique.

                Il est donc particulièrement conseillé de trouver le moyen de s'assurer que l'espace mémoire nécessaire à la représentation de tous les éléments d'une matrice soit pris sur le tas au lieu de sur la pile, principalement lorsque nous avons affaire à des matrice importantes ;) (une matrice de 3*3 ou de 4*4 int ou double ne posera pas trop de problème, une matrice de 150*200 données complexes en posera beaucoup plus ;) )

                • Partager sur Facebook
                • Partager sur Twitter
                Ce qui se conçoit bien s'énonce clairement. Et les mots pour le dire viennent aisément.Mon nouveau livre : Coder efficacement - Bonnes pratiques et erreurs  à éviter (en C++)Avant de faire ce que tu ne pourras défaire, penses à tout ce que tu ne pourras plus faire une fois que tu l'auras fait
                  25 janvier 2019 à 7:55:12

                  Et une matrice creuse ne se represente généralement pas par un tableau.

                  Donc, ca dépend.

                  Et pour des petites tailles, array d'array ca va très bien. Pas de surcoût lié aux indirections, pas de coût de gestion des libérations, localité des données, c'est bon pour le cache.

                  -
                  Edité par michelbillaud 25 janvier 2019 à 7:58:54

                  • Partager sur Facebook
                  • Partager sur Twitter
                    25 janvier 2019 à 17:29:38

                    michelbillaud a écrit:

                    Et pour des petites tailles, array d'array ca va très bien. Pas de surcoût lié aux indirections, pas de coût de gestion des libérations, localité des données, c'est bon pour le cache.

                    Ah je ne dis absolument pas le contraire!  Je dis juste que cela a beau être bon pour le cache, ca peut devenir nocif pour la pile d'appels ;)

                    Et c'est la raison pour laquelle, "au delà d'un certain point", il s'avère préférable -- lorsque l'on a affaire à des matrice pleines -- d'envisager la linéarisation des données, et donc, la mise ne place d'une notion de Matrice plus "consistante" ;)

                    • Partager sur Facebook
                    • Partager sur Twitter
                    Ce qui se conçoit bien s'énonce clairement. Et les mots pour le dire viennent aisément.Mon nouveau livre : Coder efficacement - Bonnes pratiques et erreurs  à éviter (en C++)Avant de faire ce que tu ne pourras défaire, penses à tout ce que tu ne pourras plus faire une fois que tu l'auras fait
                      25 janvier 2019 à 19:19:12

                      D'où la question : sommes-nous dans ce cas ?

                      - Dans l'exemple donné, matrice 100x100 de Tiles, soit 10 000 éléments.

                      - Taille standard de la pile (sous linux)

                      $ ulimit -a 
                      ...
                      stack size              (kbytes, -s) 8192
                      


                      8 megas (mais ça peut se changer, bien sûr). Il m'en faut plus ? ulimit -s xxxxx

                      - sizeof(Tile) ?   Inconnu.

                      - combien de Map présente en mémoire quand le programme tourne ? une, quelques unes, plusieurs, beaucoup, énormément ? On ne sait pas.

                      Donc pas de conclusion à tirer sur ce point, sinon qu'en général "il faut faire attention à ce qu'on fait" :-)

                      Et la question d'origine n'était pas de discuter la meilleure façon de représenter un tableau 2D, mais de voir comment on pouvait  initialiser un tableau 2D dans un constructeur. Faut pas se laisser égarer par ses lubies.

                      -
                      Edité par michelbillaud 25 janvier 2019 à 19:40:43

                      • Partager sur Facebook
                      • Partager sur Twitter

                      Surcharger une classe avec un tableau?

                      × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                      × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                      • Editeur
                      • Markdown