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 :

Programmation orientée objet en C


Sujet :

C

  1. #1
    Expert confirmé
    Avatar de gerald3d
    Homme Profil pro
    Conducteur de train
    Inscrit en
    Février 2008
    Messages
    2 291
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Conducteur de train
    Secteur : Transports

    Informations forums :
    Inscription : Février 2008
    Messages : 2 291
    Points : 4 941
    Points
    4 941
    Billets dans le blog
    5
    Par défaut Programmation orientée objet en C
    bonjour.

    En m'inspirant des tutoriels j'ai écrit un exemple de programmation orienté objet en C. J'ai ajouté une manière de faire de l'héritage.

    J'aimerai connaître votre sentiment à propos de ce code :
    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
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    #include <stdio.h>
    #include <stdlib.h>
     
    typedef enum {MALE, FEMELLE} SEXE;
     
    #define HUMAN(identity) identity->human
     
    typedef struct Human
    {
      /* Destructeur */
      void (*delete)(struct Human **this);
     
      /* Méthodes d'accès aux données internes */
      void (*set_sexe) (struct Human *this, SEXE sexe);
      SEXE (*get_sexe) (struct Human *this);
     
      /* Données internes */
      char sexe;
    } Human;
     
    typedef struct Identity
    {
      Human *human;
     
      /* Destructeur */
      void (*delete)(struct Identity **this);
     
      /* Données internes */
      char *name;
      unsigned char age;
      unsigned char size;
    } Identity;
     
    static void
    human_delete (Human **this)
    {
      if (!this) return;
      free (*(this));
      *(this) = NULL;
    }
     
    static void
    human_set_sexe (Human *this, SEXE sexe)
    {
      this->sexe = sexe;
    }
     
    static SEXE
    human_get_sexe (Human *this)
    {
      return this->sexe;
    }
     
    Human*
    human_new()
    {
      Human *this;
     
      this = malloc (sizeof(Human));
      if (!this)
        {
          fprintf (stderr, "Allocation memory error in human_new();\n");
          exit (1);
        }
      /* Affectation des méthodes */
      this->delete = human_delete;
      this->set_sexe = human_set_sexe;
      this->get_sexe = human_get_sexe;
     
      /* Initialisation des variables internes */
      this->sexe = MALE;
     
      return this;
    }
     
    static void
    identity_delete (Identity **this)
    {
      if (!this) return;
      Identity *identity = *this;
     
      /* Libération de l'être humain */
      HUMAN(identity)->delete (&HUMAN(identity));
     
      free (*(this));
      *(this) = NULL;
    }
     
    Identity*
    identity_new ()
    {
      Identity *this;
     
      this = malloc (sizeof(Identity));
      if (!this)
        {
          fprintf (stderr, "Allocation memory error in identity_new();\n");
          exit (1);
        }
     
      /* Allocation d'un nouvelle être humain */
      this->human = human_new ();
     
      /* Affectation des méthodes */
      this->delete = identity_delete;
     
      return this;
    }
     
    int
    main(int argc, char *argv[])
    {
      Identity *identity = NULL;
     
      identity = identity_new();
     
      HUMAN(identity)->set_sexe (HUMAN(identity), FEMELLE);
     
      switch (HUMAN(identity)->get_sexe(HUMAN(identity)))
        {
        case MALE:
          printf("La personne est de sexe masculin\n");
          break;
        default:
          printf ("La personne est de sexe feminin\n");
          break;
        }
     
      identity->delete (&identity);
      return 0;
    }

  2. #2
    Membre expérimenté Avatar de Trademark
    Profil pro
    Inscrit en
    Février 2009
    Messages
    762
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 762
    Points : 1 396
    Points
    1 396
    Par défaut
    Bonjour,

    Alors voila mes observations:

    • Déclaration de "sexe" dans Human de type "char" alors que c'est une enum de type SEXE. De manière plus général, il ne faut pas chercher à optimiser des entiers en unsigned char comme pour "age" ou "size", ça ne sert à rien et les variables "int" sont traitées plus rapidement.
    • Attention aux termes qui sont valides en C++, bien que ça ait peu d'intérêt, il vaut mieux que le code soit compilable avec g++. Les termes "this" et "delete" remplacés par "self" et "destroy" par exemple.
    • La macro HUMAN() ne fait pas très "orienté-objet". Il faudrait peut-être la remplacer par un getter bien que je ne vois pas bien l'utilité de la classe "Identity" et surtout de l'association entre celle-ci et Human.
    • Je pense qu'il faut cacher les détails d'implémentation et proposer Human comme une interface. Dans cette structure tu ne mets aucunes variables "privées" et tu crées une autre structure "Human_impl" par exemple. Ainsi tu alloues de la place pour Human_impl dans la construction et tu castes en Human lors du retour (et inversement lors des appels aux fonctions).


    Bien que vouloir faire de l'orienté-objet en C est un doux rêve car ce n'est pas possible à cause des limites du langage. On ne pourra que s'en approcher. Et plus on s'en approchera plus le coût sera conséquent en terme de mémoire et de simplicité d'utilisation, du aux nécessaires indirections. Je m'en suis rendu compte en implémentant des structures de donnée en suivant cette méthode.

  3. #3
    Expert confirmé
    Avatar de gerald3d
    Homme Profil pro
    Conducteur de train
    Inscrit en
    Février 2008
    Messages
    2 291
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Conducteur de train
    Secteur : Transports

    Informations forums :
    Inscription : Février 2008
    Messages : 2 291
    Points : 4 941
    Points
    4 941
    Billets dans le blog
    5
    Par défaut
    Tes remarques sont tout à fait justifiés. Je m'essaye simplement à ce genre de programmation. Ca me permet de triturer les pointeurs dans tous les sens (oui je sais, je suis un grand malade ).

    Bien entendu je ne cherche pas à réinventer la roue. Si j'ai besoin de programmer orienté objet j'utiliserai directement le C++. Cependant j'utilise la bibliothèque Gtk+ et elle est elle-même orientée objet (je sais il existe gtkmm pour le C++). J'essaie donc d'en comprendre le fonctionnement interne.

  4. #4
    Membre habitué
    Homme Profil pro
    Inscrit en
    Juillet 2010
    Messages
    96
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Juillet 2010
    Messages : 96
    Points : 140
    Points
    140
    Par défaut
    Voici un petit PDF intéessant sur une technique de mise en place oop en C.

    Selon moi, tant qu'à faire du oop, autant le faire en c++ sauf si c'est pour apprendre.

  5. #5
    Expert confirmé
    Avatar de gerald3d
    Homme Profil pro
    Conducteur de train
    Inscrit en
    Février 2008
    Messages
    2 291
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Conducteur de train
    Secteur : Transports

    Informations forums :
    Inscription : Février 2008
    Messages : 2 291
    Points : 4 941
    Points
    4 941
    Billets dans le blog
    5
    Par défaut
    Citation Envoyé par nault Voir le message
    ...Selon moi, tant qu'à faire du oop, autant le faire en c++ sauf si c'est pour apprendre.
    C'est tout à fait ca. Merci pour la documentation.

  6. #6
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Je remarque tu tu n'utilises pas de vtable: Chaque instance possède ses propres copies des pointeurs de fonction.

    C'est sans doute pour cela que tu hérites par pointeur au lieu d'avoir la structure elle-même dans ta structure dérivée (ce qui est un peu contre-intuitif).
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  7. #7
    Expert confirmé
    Avatar de gerald3d
    Homme Profil pro
    Conducteur de train
    Inscrit en
    Février 2008
    Messages
    2 291
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Conducteur de train
    Secteur : Transports

    Informations forums :
    Inscription : Février 2008
    Messages : 2 291
    Points : 4 941
    Points
    4 941
    Billets dans le blog
    5
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    Je remarque tu tu n'utilises pas de vtable: Chaque instance possède ses propres copies des pointeurs de fonction.

    C'est sans doute pour cela que tu hérites par pointeur au lieu d'avoir la structure elle-même dans ta structure dérivée (ce qui est un peu contre-intuitif).
    J'avoue ne pas connaître les vtable. J'ai donc commencé quelques recherches à ce sujet. Je ne trouve pour l'instant que des références en C++.

    L'idéal serait en effet de retrouver la structure parente dans la structure dérivée. Mais hormis de recopier son contenu dans la déclaration de la structure fille, je ne vois pas trop comment faire en C.

    Pourrais-tu me donner une exemple basique de ce fonctionnement ?

  8. #8
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Pour la vtable, c'est juste un niveau d'indirection supplémentaire: Le premier membre d'une classe, dérivée ou non, est toujours un pointeur vers la vtable. Une interface ne contient que le pointeur en question.

    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
    struct Human;
     
    struct HumanVtable
    {
    	/* Destructeur */
    	void (*delete)(struct Human **this);
     
    	/* Méthodes d'accès aux données internes */
    	void (*set_sexe) (struct Human *this, SEXE sexe);
    	SEXE (*get_sexe) (struct Human *this);
    };
     
    struct Human
    {
    	struct HumanVTable const * pVTbl;
    	SEXE sexe;
    };
     
    struct HumanVTable const g_HumanVTable = {
    	Human_delete,
    	Human_set_sexe,
    	Human_get_sexe
    };
    Pour la classe dérivée, c'est à peu près pareil mais elle contient un Human au lieu d'un Human*. Il faudra sans doute des casts dans le remplissage de la vtable, mais ce n'est pas trop un problème.

    Note que la déclaration de IdentityVtable aussi incluera HumanVtable.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

Discussions similaires

  1. Problème de programmation orientée objet
    Par dan65 dans le forum WinDev
    Réponses: 8
    Dernier message: 17/09/2006, 01h04
  2. Réponses: 2
    Dernier message: 30/03/2006, 14h48
  3. [C#] Comment correctement programmer orienté objet ?
    Par ChristopheOce dans le forum C#
    Réponses: 5
    Dernier message: 06/02/2006, 13h22
  4. [POO] apprendre la programmation orientée objet
    Par Invité dans le forum Langage
    Réponses: 5
    Dernier message: 10/12/2005, 11h33
  5. [DEBUTANT] Conseil sur la programmation orienté objet
    Par etiennegaloup dans le forum Langage
    Réponses: 7
    Dernier message: 27/05/2005, 12h59

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