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 :

C et C++ (différences).


Sujet :

C++

  1. #1
    Membre expérimenté
    Avatar de Luke spywoker
    Homme Profil pro
    Etudiant informatique autodidacte
    Inscrit en
    Juin 2010
    Messages
    1 077
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Etudiant informatique autodidacte

    Informations forums :
    Inscription : Juin 2010
    Messages : 1 077
    Points : 1 742
    Points
    1 742
    Par défaut C et C++ (différences).
    Salut les C++,

    je m'incruste un peu dans la discussion et je ne sais si je suis la bienvenue.

    Je pratique le python depuis 5 ans et le C depuis 2 ans.

    Le but de ma question est d'aller a la pêche au infos concernant le C++.

    std::vector, Array, Vector...
    Est-ce les tableaux dont vous parlez ont des méthodes internes comme append(), insert(), pop()... ?

    Array est un tableau C/C++ "déguisé" statique ( pas de new/malloc) plus sécuritaire.
    Vector est un tableau C/C++ "déguisé" dynamique ( new/malloc ) plus sécuritaire.
    Est-ce que la gestion de la mémoire est protégée en C++ (automatique) ?

    Le but et de pêcher des infos avant de m'investir dans l'apprentissage du C++.

    Merci pour vos précieuses réponses éclairées.

    PS: désolé pour l'incrustation dans la discussion de joffrey575, mais c'était trop tentant car je me pose ces questions, entre autres, depuis trop longtemps.
    Pour faire tes armes:
    Use du présent pour construire ton futur sinon use de ce que tu as appris auparavant.
    Et sois toujours bien armé avant de te lancer.
    Le hasard ne sourit qu'aux gens préparés...
    Site: Website programmation international (www.open-source-projects.net)
    Site: Website imagerie 3D (www.3dreaming-imaging.net)
    Testez aux moins pendant une semaine l'éditeur avec terminaux intégrées it-edit Vous l'adopterai sûrement !
    FUN is HARD WORK !!!

  2. #2
    Membre émérite
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Points : 2 799
    Points
    2 799
    Par défaut
    Les tableaux dynamiques ont des méthodes push_back, pop_back. Les tableaux statiques n’en ont pas : leur taille est fixe (je crois que ce concept n’existe pas en python).

    En c++, la gestion de la mémoire (et des ressources en général) est... automatique si tu le souhaites, manuelle si tu le souhaites. Le mot d’ordre est RAII/RFID (Resource Acquisition Is Initialization, Resource Finalization Is Destructor), qui sont deux acronymes barbares pour dire en gros qu’une ressource doit être acquise dans un constructeur est libérée dans un destructeur, ce qui permet de connaître précisément sa durée de vie.

    Venant du C, il te faudra oublier un certain nombre de choses (par exemple, les pointeurs, l’allocation avec malloc, etc) pour te mettre au C++, afin de ne pas tomber dans les travers du « C with classes » qu’on voit un peu trop souvent, et qui est une très mauvaise manière de faire du C++.

  3. #3
    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 963
    Points
    32 963
    Billets dans le blog
    4
    Par défaut
    les tuples pourraient être vus comme l'équivalent Python des array C++ amha
    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.

  4. #4
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 612
    Points
    30 612
    Par défaut
    Salut,
    Citation Envoyé par Luke spywoker Voir le message
    Salut les C++,

    je m'incruste un peu dans la discussion et je ne sais si je suis la bienvenue.

    Je pratique le python depuis 5 ans et le C depuis 2 ans.

    Le but de ma question est d'aller a la pêche au infos concernant le C++.



    Est-ce les tableaux dont vous parlez ont des méthodes internes comme append(), insert(), pop()... ?
    Toutes les collections de la STL proposent un certain nombre de fonctions membres, mais ne proposent que les fonctions qui sont adaptées au type de collection envisagé.

    Ainsi, std::vector (tableau de taille dynamique) et std::list (liste chainée) proposent (entre autre) [/codeinline]push_back[/codeinline], pop_back, insert alors que std::set (arbre binaire de recherche) et std::map (tableau associatif "clé/valeur" utilisant un arbre binaire de recherche sur la clé) proposent que insert, erase et find car... il n'y a pas de sens à vouloir obliger un nouvel élément à se trouver "en dernière position" dans un arbre binaire. De la même manière, std::stack (pile LIFO) et std::queue (file FIFO) ne proposeront que push, et pop car on place forcément le nouvel élément "après les autres".

    Pour pouvoir utiliser correctement ces collections, il est souvent intéressant d'aller voir du coté de cppreference.com ou de cplusplus.com afin d'avoir la documentation complète, mais, de manière générale, les noms de fonctions restent "logiques" par rapport à l'utilisation qui est faite de ces collections
    Est-ce que la gestion de la mémoire est protégée en C++ (automatique) ?
    Pas forcément :
    C++11 (l'avant dernière norme en date) est venue avec la notion de "pointeurs intelligents" (std::unique_ptr et le couple std::shared_ptr /std::weak_ptr) qui s'assurent que la mémoire allouée dynamiquement est correctement libérée avant de perdre le pointeur.

    Tu te douteras que l'on pousse un maximum les gens à les utiliser car cela permet de gagner énormément en robustesse au niveau des programmes développés

    Cependant, bien que nous essayerons de t'en dissuader, tu peux aussi prendre (l'énorme) le risque de vouloir gérer toi-même la mémoire à la main. Tu peux le faire... mais ce n'est très certainement pas la meilleure décision que tu prendra

    Bien sur, toutes les collections de la STL gèrent également parfaitement la mémoire qui leur est allouée, mais uniquement celle pour laquelle elles ont elles-même fait la demande de la mémoire. Si tu places un pointeur "nu" représentant une adresse mémoire allouée par new dans une collection, la destruction de la collection n'aura pas pour effet d'invoquer delete sur ce pointeur.

    Par contre, si tu places un pointeur intelligent dans une collection de la STL, la collection se chargera de la mémoire qu'elle a elle-même demandée et le pointeur intelligent se chargera de la mémoire que tu as demandée, et tu auras quelque chose de particulièrement robuste
    Le but et de pêcher des infos avant de m'investir dans l'apprentissage du C++.
    Il n'y a aucun problème, mais garde toujours en tête que, bien que C++ "descend" du C (un peu comme le francais descend du latin de Jules Cesar), il s'agit de deux langages totalement différents, tant dans leur philosophie que dans la manière d'aborder certains problèmes.

    Beaucoup de "bonnes pratiques" dont on peut te rabattre les oreilles en C sont considérées comme mauvaises, dangereuses et nocives en C++. Au final, le seul gros avantage que tu auras à avoir pratiqué le C, c'est que tu connais la syntaxe de base (et encore, tu n'en connais qu'une partie) et que tu es sans doute habitué au système d'inclusion et à tout ce qui a trait au préprocesseur
    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

  5. #5
    Membre chevronné

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Avril 2013
    Messages
    610
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

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

    Informations forums :
    Inscription : Avril 2013
    Messages : 610
    Points : 1 878
    Points
    1 878
    Billets dans le blog
    21
    Par défaut
    Est-ce que la gestion de la mémoire est protégée en C++ (automatique) ?
    C'est un peu LA question centrale du C++ ! Le créateur du langage considère que la gestion automatique par un garbage collector (la solution retenue par la plupart des langages récents, de Java à Python en passant par Haskell ou Ruby), quoiqu'elle puisse être une solution adaptée à certains cas de figure, ne doit pas être la méthode par défaut et encore moins la seule méthode. En conséquence, le C++ propose différentes manières de gérer la mémoire:

    Sur le "tas" (allocation dynamique de la mémoire):
    1. comme le C avec les fonctions C: ce n'est pas recommandé mais toutes les fonctions standards du C sont disponibles en C++ (free, malloc, realloc, calloc, etc.).
    2. comme le C avec les opérateurs C++: les opérateurs new et delete remplacent free et malloc (avec des tas de nuances très subtiles, qu'il est parfois difficile de s'approprier). Il faut en revanche être cohérent: on ne peut pas libérer avec un opérateur C++ la mémoire allouée avec une fonction C et vice-versa. NB: il y a plusieurs new et plusieurs delete.
    3. comme le C avec les opérateurs C++ au sein des classes: une classe définit un constructeur qui alloue la mémoire et un destructeur qui la libère. Si ce travail est fait correctement, la classe peut être utilisée sur la pile comme un type natif sans se préoccuper plus de la gestion de la mémoire. La bibliothèque standard définit un bon nombre de classes (vector, string, map, etc.) où ce travail est déjà fait.
    4. la méthode 3 peut être généralisée dans 2 directions:
    4.a. RAII: ce n'est plus seulement la mémoire mais toute ressource partagée qui est allouée/libérée par le couple constructeur/destructeur: les fichiers, connexions aux bases de données, sockets, etc.
    4.b. les pointeurs intelligents (qui gèrent allocation et destruction de la mémoire sur laquelle ils pointent) permettent d'appliquer l'idiome RAII à n'importe quelle allocation dynamique, sans définition d'une classe spécifique.
    5. la norme C++ prévoit que le langage offre le support nécessaire à la création d'un garbage-collector. Je ne connais pas bien le sujet mais il est fort possible que tu puisses en trouver un sous la forme de bibliothèque.

    Sur la "pile"
    Dans ces cas-là, pas de gestion explicite de la mémoire!

    En conclusion, je pense que tu fais bien de te lancer dans le C++ qui est très différent et de C et de Python. Un bon point de départ est le livre de B. Stroustrup: programming principles using C++ (http://www.stroustrup.com/programming.html)

  6. #6
    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 stendhal666 Voir le message
    Sur la "pile"
    Dans ces cas-là, pas de gestion explicite de la mémoire!
    Avec quand même une nuance, on sait quand l'objet va être supprimé. Avec un garbage collector on à rarement cette garantie: l'objet va être supprimé à un moment ou à un autre, mais on ne sait pas quand.

  7. #7
    Membre expérimenté
    Avatar de Luke spywoker
    Homme Profil pro
    Etudiant informatique autodidacte
    Inscrit en
    Juin 2010
    Messages
    1 077
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Etudiant informatique autodidacte

    Informations forums :
    Inscription : Juin 2010
    Messages : 1 077
    Points : 1 742
    Points
    1 742
    Par défaut
    Merci beaucoup pour toutes vos réactions didactiques,

    Et j'ai une bonne nouvelle:

    Je vient de débuter le C++, 200 pages d'un livre depuis le poste.

    En faîtes pour l'instant j'apprends donc je n'ai pas grand chose a dire, mais vous en avez déjà dit beaucoup.

    Avec tous les conteneurs, je n'ai pas vue de méthode pour libéré les conteneurs afin de les détruire alors doit ont laisser la masse de mémoire allouer s'amasser, a moins de faire une boucle:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    while ( vec.size() != 0 ) { 
      vec.pop_back() 
    }
    afin que la mémoire soit désallouer par des mécanismes internes.

    Bon il y a une part de réponse dans le poste de stendhal666 et la création personnel d'un Garbage collector...

    Je posterai dans le forum adapté et vous laisse la main pour répondre a la question initiale, pendant ce temps je vais me retirer dans mon bureau afin d'apprendre les rouages du C++.

    Merci pour vos réponses.
    Pour faire tes armes:
    Use du présent pour construire ton futur sinon use de ce que tu as appris auparavant.
    Et sois toujours bien armé avant de te lancer.
    Le hasard ne sourit qu'aux gens préparés...
    Site: Website programmation international (www.open-source-projects.net)
    Site: Website imagerie 3D (www.3dreaming-imaging.net)
    Testez aux moins pendant une semaine l'éditeur avec terminaux intégrées it-edit Vous l'adopterai sûrement !
    FUN is HARD WORK !!!

  8. #8
    Membre émérite
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Points : 2 799
    Points
    2 799
    Par défaut
    Avec les conteneurs standards, tu ne t’occupes en général pas de « libérer la mémoire ». Si tu veux vider ton conteneur, tu peux utiliser la méthode « clear » : cela détruira chacun des éléments du conteneur, mais en revanche la mémoire allouée par le conteneur lui-même ne sera pas libérée. Si tu veux vraiment libérer cette mémoire elle-même, tu peux utiliser la méthode « shrink_to_fit ».

    Mais tu ne le feras que très rarement, en effet :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    int f(bool toto)
    {
      if(toto)
      {
          std::vector<int> v;
          for(int i = 0; i < 1000; ++i)
              v.push_back(i);
          return v.capacity(); // v sera automatiquement détruit ici, la mémoire allouée libérée.
      }
      else
        return 0;
    }
    C’est une différence assez majeure et fondamentale avec C, qui simplifie énormément la vie. En C++, la question fondamentale est « quelle est la durée de vie de mes resources ? ».

  9. #9
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 189
    Points : 17 141
    Points
    17 141
    Par défaut
    En cours de vie de la collection, tu peux utiliser clear().

    Et surtout, le destructeur d'une collection désalloue sa mémoire interne.
    Chaque élément est alors détruit par son destructeur propre.
    Cela ne pose problème qu'avec un pointeur, car le "destructeur" d'un pointeur (comme tout type primitif) est simplement de l'oublier. Il n'y a pas d'appel à delete.

    C'est à l'utilisateur de libérer son vecteur, s'il a alloué les pointeurs. (par symétrie: qui alloue libère)
    Ce que tu peux écrire ainsi: for(auto p : collection) delete p;.

    pop_back() retire l'élément de la collection, mais ca ne libère pas forcément la mémoire. Ca dépend de la collection: une liste chainée la libérera, pas un vecteur. Quant au deque, je ne sais plus.

    En C++, on se repose énormément sur le destructeur pour poser des garanties.
    En effet, cette fonction possède une propriété extraordinaire: elle est appelée une et une seule fois pour chaque variable (dont le constructeur n'a pas levé d'exception).
    Cette propriété est au coeur d'un principe que tu vas apprendre à connaitre et à aimer: le RAII.

    L'idée, c'est que le constructeur d'une classe acquiert une ressource chère, et son destructeur la libère.
    Il y a plusieurs exemples plus ou moins anciens
    • std::string contient un pointeur vers un tableau de caractères.
    • std::vector<T> contient un pointeur vers un tableau de T
    • std::unique_ptr<T> contient/est un pointeur vers un T, et s'assure d'en être l'unique propriétaire. Ce faisant, il sait pouvoir faire son delete sans soucis.
    • std::fstream contient un fichier qu'il ouvre et ferme judicieusement.



    Comme une variable est libérée dès qu'on sort de sa portée de déclaration (son scope), il suffit de déclarer les variables au "dernier moment".

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #include <fstream>
    int main () {
        int i;
        {
            std::ifstream fichier("chemin.txt");
            fichier >> i;
        }//c'est ici que la variable fichier est détruite, et donc que fichier.~ifstream() est appelée, fermant le fichier.
        i*=2;
        //on peut faire plein de chose, encore, ce n'est pas un soucis, le fichier est déjà fermé :D
        return i;
    }
    La conséquence, c'est qu'il peut devenir utile de faire une petite capsule pour les contextes obtenus dans les bibliothèques C.
    Prenons l'exemple de la SDL, une bibliothèque graphique.
    Voici l'exemple de base, pris sur leur site
    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
    int main(int argc, char** argv) {
        capsule_SDL sdl(
        if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER) != 0) {
            fprintf(stderr,
                    "\nUnable to initialize SDL:  %s\n",
                    SDL_GetError()
                   );
            return 1;
        }
        atexit(SDL_Quit);
     
        /* ... */
     
        return 0;
    }
    Remarque le magnifique atexit(), qu'on pourrait oublier.


    Avec un minimum de propreté, une capsule pourrait s'écrire ainsi:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    /* une exception */
    struct SDL_exception : std::runtime_error {
        SDL_exception() : std::runtime_error(SDL_GetError()) {}
    };
     
    /* la capsule proprement dite */
    class SDL {
        SDL(Uint32 mode) {
            if (SDL_Init(mode) != 0) throw SDL_exception();
        }
     
        ~SDL() {SDL_Quit();}
    };
    L'avantage immédiat, c'est que l'exemple devient maintenant:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    int main(int argc, char** argv) {
        try {
            SDL sdl(SDL_INIT_VIDEO|SDL_INIT_TIMER);
            /* PAS de atexit(SQL_Quit); */
            /* ... */
            return 0;
        } catch (SDL_exception const& e) {
            std::cerr << "Unable to initialize SDL:  "<<e.what() << std::endl;
            return 1;
        }
    }
    J'ai la même gestion d'erreur, mais par contre, je n'ai plus du tout à m'inquiéter de la fermeture.

    En effet, quelle que soit la façon dont on quitte le programme, je sais qu'on aura un appel à SQL_Quit.

    Dans un vrai code, il faudrait ajouter un namespace (ou plusieurs) autour de cette capsule, pour éviter tout risque d'interférence avec la bibliothèque.
    J'ai en général tendance à utiliser deux namespaces, raii en premier, puis le nom de la bibliothèque. ainsi, la classe serait raii::sdl::sdl.

    PS: J'aurai pu être encore plus vicieux, et écrire ma classe en gardant le atexit, mais en interne:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    struct SDL {
        SDL(Uint32 mode) {
            if (SDL_Init(mode) != 0) throw SDL_exception();
            atexit(SDL_Quit);
        }
    };
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  10. #10
    Membre chevronné

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Avril 2013
    Messages
    610
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

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

    Informations forums :
    Inscription : Avril 2013
    Messages : 610
    Points : 1 878
    Points
    1 878
    Billets dans le blog
    21
    Par défaut
    Ah non, rien de tel!

    1. mettons que tu déclares un vecteur de string:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    { // début de la portée
      std::vector<std::string> vs;
      /*
      là tu le remplis
      */
    } // lorsqu'on sort de la portée où vs est déclaré, tous les éléments du vector sont détruits (leur destructeur est appelé) ainsi que vs lui-même.
    2. Ce comportement (hautement désirable) n'est en revanche pas suivi si tu déclares un vecteur de pointeurs sur des strings:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    { // début de la portée
      std::vector<std::string*> vs;
      /*
      là tu le remplis
      */
    } // lorsqu'on sort de la portée où vs est déclaré, les pointeurs contenus dans vs disparaissent (ce sont des copies des originaux) mais pas les strings sur lesquels ils pointent
    La conclusion c'est qu'il faut toujours préférer l'option 1, qui applique l'idiome RAII (les ressources sont acquises par le vecteur qui se chargera de leur libération), lorsqu'elle est suffisante. Le seul cas où elle ne l'est pas est lorsqu'un comportement polymorphique est recherché (pointeur sur une hiérarchie de classes, lorsque la fonction à appeler dépend de l'objet sur lequel le pointeur pointe), mais c'est peut-être pour plus tard dans ton apprentissage.

  11. #11
    Membre émérite
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 764
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 764
    Points : 2 704
    Points
    2 704
    Par défaut
    Puisque tu passes au C++ depuis Python, je en peux que te suggérer que d'employer à outrance le const ; la notion n'est guère présente en Python.
    J'ai fait quant à moi le chemin inverse ces derniers mois (C++ -> Python), et j'ai souffert (pour moi, Python est un peu un langage de hippies, comparé à C++).

  12. #12
    Membre émérite
    Avatar de prgasp77
    Homme Profil pro
    Ingénieur en systèmes embarqués
    Inscrit en
    Juin 2004
    Messages
    1 306
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Eure (Haute Normandie)

    Informations professionnelles :
    Activité : Ingénieur en systèmes embarqués
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Juin 2004
    Messages : 1 306
    Points : 2 466
    Points
    2 466
    Par défaut
    Citation Envoyé par oodini Voir le message
    Python est un peu un langage de hippies
    Nom : cartman.jpeg
Affichages : 322
Taille : 18,0 Ko

    Désolé .
    -- Yankel Scialom

  13. #13
    Membre expérimenté
    Avatar de Luke spywoker
    Homme Profil pro
    Etudiant informatique autodidacte
    Inscrit en
    Juin 2010
    Messages
    1 077
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Etudiant informatique autodidacte

    Informations forums :
    Inscription : Juin 2010
    Messages : 1 077
    Points : 1 742
    Points
    1 742
    Par défaut
    Resalut les gars ++,

    le python est parfait pour débuter la programmation quand on y connait rien, après le C ouvre beaucoup de portes et ce qui tourne autour du C/C++ ca enseigne pas mal de choses avec un brin d'assembleur c'est nickel !!!

    Effectivement le "C-Like C++" est absolument a éviter d'après ce que j'ai lu et la notion de scope qu'une variable n'existe que dans sa porté est pas mal car automatiquement détruit.


    Mais j'ai une petite question que je pense de mes 200 pages de lectures sur le C++ non résolvable.

    Je vais vous l'expliquer en pseudo C++ en ommétant des choses:

    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
     
    class Point {
     
      public :
       ...
     
       /** Operator overloading Point + Point == Line **/
       Line operator + (Point p) ;
     
    }
     
    class Line {
     
      public :
     
      /** Contructor **/
      Line(Point p1, Point P2) ;
     
      ...
    }
    En faite j'aimerai utiliser un objet de type Point dans mon contructeur d'objet de type Line
    et aussi avoir une méthode de de la classe Point qui renvoie un objet de type Line (ici par surcharge d'opérateur).

    Ce que je pense pas possible étant donnée que l'une des deux classes doit être déclaré avant l'autre ce qui fait qu'on ne peut pas faire appel a l'autre avant sa déclaration ???
    Pour faire tes armes:
    Use du présent pour construire ton futur sinon use de ce que tu as appris auparavant.
    Et sois toujours bien armé avant de te lancer.
    Le hasard ne sourit qu'aux gens préparés...
    Site: Website programmation international (www.open-source-projects.net)
    Site: Website imagerie 3D (www.3dreaming-imaging.net)
    Testez aux moins pendant une semaine l'éditeur avec terminaux intégrées it-edit Vous l'adopterai sûrement !
    FUN is HARD WORK !!!

  14. #14
    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
    Point + Point == Line n'a pas vraiment de sens :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    Point a;
    Point b;
     
    auto result = a + b; // result de type Line
    auto result = a += b; // result de type Point
    Mais disons que c'est pas grave.

    Tu as 2 façons de résoudre ce genre de problèmes :
    Avec une déclaration anticipée (solution générale).
    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
    class Point; // déclaration anticipée : on donne seulement le nom de la classe
     
    class Line {
    public :
     
    	// ctor, pas besoin de la déclaration complète de la classe pour
    	// utiliser des refs : on peut référencer le type.
    	// il faudra par contre fournir la déclaration de Point lors
    	// de l'implémentation
    	Line(Point const& p1, Point const& P2);
    };
     
    class Point {
    public:
    	// Operator overloading Point + Point == Line
    	Line operator+(Point const& p) const; 
    };
    En utilisant le fait que operator+ n'a pas besoin d'être une fonction membre:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    class Point {
    	double x, y;
    };
     
    class Line {
    public :
    	Line(Point const& p1, Point const& P2);
    };
     
    // operator+ est donc une fonction libre, Line et Point sont déclarés à ce moment
    Line operator+(Point const& lhs, Point const& rhs);

  15. #15
    Membre chevronné

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Avril 2013
    Messages
    610
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

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

    Informations forums :
    Inscription : Avril 2013
    Messages : 610
    Points : 1 878
    Points
    1 878
    Billets dans le blog
    21
    Par défaut
    Si, si, ne t'inquiète pas... Mais il est vrai que c'est une source de problèmes quand deux classes se font référence mutuellement, problèmes qui disparaissent assez vite à condition de suivre certaines bonnes pratiques.

    En l'occurrence tu fais à mon avis une faute conceptuelle parce que tu couples trop étroitement tes deux classes. Si une ligne est définie par des points, la classe des points est "antérieure" logiquement à celle des lignes et ne devrait pas y faire référence. De plus une classe Point a bien d'autres usages que de créer des lignes, et il serait dommage d'avoir à compiler la classe ligne à chaque fois que tu utiliseras Point, y compris pour un autre usage. Dans la même ligne, je crois que la surcharge d'opérateur est mal employée: l'addition de deux points peut retourner une ligne, mais aussi bien un vecteur, un rectangle ou je ne sais quoi.

    L'usage serait plutôt de créer tes classes dans deux fichiers différents (ou plutôt quatre, deux par classe, un pour la déclaration et l'autre pour la définition):
    Code C++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    // point.h
    class Point { ... };

    Code C++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    // line.h
    #include "point.h"
    class Line {
      ...
      Line(const Point& a, const Point& b);
      ...
    };

    Néanmoins, si tu veux persister dans la surcharge d'opérateur, il n'est pas nécessaire de le définir dans la class Point. Tu peux le faire dans le fichier "line.h", en dehors de la class Line:
    Code C++ : Sélectionner tout - Visualiser dans une fenêtre à part
    Line operator+(const Point& a, const Point& b);

    Définir les opérateurs de surcharge en dehors du corps de la classe est une bonne pratique. Cela permet de conserver l'encapsulation des données: les opérateurs font référence à un accesseur offert par la classe et n'ont pas à être modifiés un par un si tu en changes l'implémentation.

    En tout cas je te rejoins sur un point, 200p de C++ ce n'est pas suffisant pour connaître toutes les subtilités de l'édition des liens, qui est une des difficultés particulières du couple C/C++, surtout quand on vient de langages où les modules sont implémentés (le C++ pourrait évoluer dans ce sens, d'ailleurs).

  16. #16
    Membre chevronné

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Avril 2013
    Messages
    610
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

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

    Informations forums :
    Inscription : Avril 2013
    Messages : 610
    Points : 1 878
    Points
    1 878
    Billets dans le blog
    21
    Par défaut
    Citation Envoyé par Iradrille Voir le message
    Tu as 2 façons de résoudre ce genre de problèmes :
    Avec une déclaration anticipée (solution générale).[code]class Point; // déclaration anticipée : on donne seulement le nom de la classe

    class Line {
    public :

    // ctor, pas besoin de la déclaration complète de la classe pour
    // utiliser des refs : on peut référencer le type.
    // il faudra par contre fournir la déclaration de Point lors
    // de l'implémentation
    Line(Point const& p1, Point const& P2);
    };
    +1 pour la rapidité mais:
    une déclaration anticipée ne permet pas d'utiliser complètement la classe. On peut utiliser simplement un pointeur sur la classe, parce qu'il faut que la taille de l'objet soit connue lors de la compilation, ce qui n'est pas le cas lors d'une simple déclaration.

  17. #17
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 189
    Points : 17 141
    Points
    17 141
    Par défaut
    Un pointeur ou une référence...
    Nous avons dans la faq une question sur ce sujet
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  18. #18
    Membre chevronné

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Avril 2013
    Messages
    610
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

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

    Informations forums :
    Inscription : Avril 2013
    Messages : 610
    Points : 1 878
    Points
    1 878
    Billets dans le blog
    21
    Par défaut
    Indeed. Je voulais souligner qu'une déclaration anticipée ne ferait pas l'affaire pour:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    class Line;
    class Point {
    ...
      Line operator+ (const Point& a, const Point& b);
    };
    Où un objet line est construit...

    Mais effectivement ce n'est pas le bout de code qu'Iradrille visait

  19. #19
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 189
    Points : 17 141
    Points
    17 141
    Par défaut
    Tu es sur de ca? il me semble que pour un type de retour, ca pouvait aller
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  20. #20
    Membre chevronné

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Avril 2013
    Messages
    610
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

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

    Informations forums :
    Inscription : Avril 2013
    Messages : 610
    Points : 1 878
    Points
    1 878
    Billets dans le blog
    21
    Par défaut
    Pour être tout à fait exact, on peut déclarer une fonction qui retourne un type qui n'a pas été défini, mais on ne peut pas définir une fonction qui retourne un type qui n'a pas été défini.
    Encore une de ces joyeusetés du système de compilation/édition de liens du C/C++...

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. Différence entre un "bidouilleur" et un Pro ?
    Par christ_mallet dans le forum Débats sur le développement - Le Best Of
    Réponses: 290
    Dernier message: 28/11/2011, 10h53
  2. Différence entre TCP, UDP, ICMP
    Par GliGli dans le forum Développement
    Réponses: 1
    Dernier message: 13/09/2002, 08h25
  3. [CR][Jetform] Quelles sont les différences ?
    Par littlecow dans le forum SAP Crystal Reports
    Réponses: 2
    Dernier message: 23/07/2002, 11h40
  4. Différences entre jmp, jz, jnz, etc
    Par christbilale dans le forum Assembleur
    Réponses: 3
    Dernier message: 05/07/2002, 15h09
  5. Réponses: 3
    Dernier message: 07/05/2002, 16h06

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