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 :

Questions sur l'héritage multiple


Sujet :

C++

  1. #1
    Membre éprouvé
    Avatar de beegees
    Homme Profil pro
    Développeur Web
    Inscrit en
    Mars 2004
    Messages
    3 610
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2004
    Messages : 3 610
    Points : 1 277
    Points
    1 277
    Par défaut Questions sur l'héritage multiple
    Bonjour tout le monde,

    J'ai une question sur l'héritage multiple (enfin il me semble que ce cas est de l'héritage multiple --> à confirmer) :

    J'ai une classe CChargeurFichierTexte :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    class CChargeurFichierTexte : public CChaineComposee
    {
    public:
    	CChargeurFichierTexte();
    	~CChargeurFichierTexte();
    
    	bool			Charger(const char* NomFichier, char UnSeparateur, bool (* FctnTraiterLigne)(const CChargeurFichierTexte&, void*), void* Contexte);
    
    private:
    };
    on voit qu'elle hérite des objets publics de CChaineComposee :

    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 CChaineComposee : private CChaine
    {
    public:
    	CChaineComposee();														// Constructeur par défaut
    	CChaineComposee(const CChaineComposee& Source);							// Constructeur par copie
    	CChaineComposee(const char* UneChaine, char UnSeparateur);				// Constructeur spécifique
    	~CChaineComposee();														// Destructeur
    
    	long			NombreChamps() const;									// Accesseur du nombre de champs
    	const char*		Champs(long Indice) const;								// Accesseur d'un champ
    
    	bool			Definir(const char* UneChaine, char UnSeparateur);		// Modificateur permettant de modifier la chaîne et de générer le tableau des champs
    
    private:
    	bool			Decomposer(char UnSeparateur);							// Modificateur permettant de modifier la chaîne et de générer le tableau des champs
    
    private:
    	long			m_NbrChamps;
    	char**			m_Champs;
    };
    Qui elle même hérite de CChaine :

    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
    class CChaine
    {
    public:
    	CChaine();																// Constructeur par défaut
    	CChaine(const CChaine& Source);											// Constructeur par copie
    	CChaine(const char* UneChaine);											// Constructeur spécifique
    	~CChaine();																// Destructeur
     
    	const char*		Chaine() const;											// Accesseur du texte de la chaîne
    	bool			EstNull() const;										// Accesseur de test sur le texte (m_Chaine == NULL)
    	bool			EstVide() const;										// Accesseur de test sur le texte (m_Chaine == NULL) || (m_Chaine == "")
     
    	void			Vider();												// Modificateur permettant de supprimer le texte de la chaîne (on revient à NULL)
    	bool			Chaine(const char* UneChaine);							// Modificateur du texte de la chaîne
     
    private:
    	char*			m_Chaine;												// Membre contenant l'adresse du tableau de caractères alloué dynamiquement
    };
    - On parle bien d'héritage multiple ici ?

    - Est-ce que la classe CChargeurFichierTexte hérite de quelque chose de la classe CChaine ?
    - CChaineComposee a un héritage private de CChaine, elle hérite de quoi alors de cette classe là ?

    Un super grand merci d'avance pour votre aide et un super bon dimanche.

    beegees

  2. #2
    Membre à l'essai
    Profil pro
    Étudiant
    Inscrit en
    Mars 2008
    Messages
    8
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mars 2008
    Messages : 8
    Points : 10
    Points
    10
    Par défaut
    Bonjour,

    Alors pour répondre à ta première question, non ce n'est pas de l'héritage multiple, ce qu'on appelle héritage multiple c'est lorsqu'une classe hérite de plusieurs autres classes. Exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    class A
    {
    // une classe A
    }
    class B
    {
    // une classe B
    }
    class AB : A, B
    {
    // une classe qui est à la fois une classe B et une classe A
    }
    Ainsi chez toi c'est plutôt simplement un héritage successif.

    Pour répondre à ta seconde question, dans un héritage, la classe fille possède toujours TOUS les éléments de sa classe mère (qui elle même possède les éléments de sa classe mère, etc...). Le marqueur de visibilité (public, protected, private) change comme son nom l'indique la visibilité à l'extérieure de la classe.

    Ainsi dans ton cas, la classe CChargeurFichierTexte contient bien l'ensemble des attributs de sa classe grand-mère, mais le marqueur de visibilité private sur l'héritage de sa classe mère l'empêche d'y avoir accès (même si elle les contient, ils lui sont masqués).
    En fait, on peut considérer que dans une classe fille est toujours instanciée sa classe mère.

    Enfin pour répondre à ta dernière question, le marqueur private sur l'héritage de CChaine ne change rien au sein de la classe CChaine, par contre cela modifie l'accessibilité aux attributs et méthodes de sa classe mère de l'extérieure (en fait comme un attribut). Encore une fois, la classe hérite de TOUS les attributs de sa classe mère, ce qui change c'est juste la visibilité.

    Mos

  3. #3
    Membre éprouvé
    Avatar de beegees
    Homme Profil pro
    Développeur Web
    Inscrit en
    Mars 2004
    Messages
    3 610
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2004
    Messages : 3 610
    Points : 1 277
    Points
    1 277
    Par défaut
    Bonjour Mos,

    Un tous grand merci pour ta réponse hyper précise.

    Alors pour répondre à ta première question, non ce n'est pas de l'héritage multiple, ce qu'on appelle héritage multiple c'est lorsqu'une classe hérite de plusieurs autres classes. Exemple :

    Code :

    class A
    {
    // une classe A
    }
    class B
    {
    // une classe B
    }
    class AB : A, B
    {
    // une classe qui est à la fois une classe B et une classe A
    }
    Ainsi chez toi c'est plutôt simplement un héritage successif.
    Merci, ça s'est clair dans mon esprit maintenant.

    S'est ici que je coince :

    Pour répondre à ta seconde question, dans un héritage, la classe fille possède toujours TOUS les éléments de sa classe mère (qui elle même possède les éléments de sa classe mère, etc...). Le marqueur de visibilité (public, protected, private) change comme son nom l'indique la visibilité à l'extérieure de la classe.

    Ainsi dans ton cas, la classe CChargeurFichierTexte contient bien l'ensemble des attributs de sa classe grand-mère, mais le marqueur de visibilité private sur l'héritage de sa classe mère l'empêche d'y avoir accès (même si elle les contient, ils lui sont masqués).
    En fait, on peut considérer que dans une classe fille est toujours instanciée sa classe mère.
    J'ai un exemple ci-dessous :

    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
    //Listing 12.2 Utilisation d'un objet dérivé
    #include <iostream>
    #include <BasicConsole.h>
    using std::cout;
    using std::endl;
    
    enum RACE { GOLDEN, CAIRN, DANDIE, SHETLAND, DOBERMAN, LAB };
    
    class Mammifere
    {
     public:
        // constructeurs 
        Mammifere():wAge(2), wPoids(5){}
        ~Mammifere(){}
     
        // méthodes d'accès
        int LireAge() const   { return wAge; }
        void DefAge(int age) { wAge = age; }
        int LirePoids() const { return wPoids; }
        void DefPoids(int Poids) { wPoids = Poids; }
     
        // autres méthodes 
        void Crier()const 
            { cout <<"Le cri du mammifere !\n"; }
        void Dormir()const { cout << "Chut. Je dors.\n"; }
     
     protected:
        int wAge;
        int wPoids;
     };
     
     class Chien : public Mammifere
     {
     public:
     
        // constructeurs 
        Chien():wRace(GOLDEN){}
        ~Chien(){}
     
        // méthodes d'accès
        RACE LireRace() const { return wRace; }
        void DefRace(RACE race) { wRace = race; }
     
        // autres méthodes 
        void RemuerQueue() const 
             { cout << "Remue la queue...\n"; }
        void Quemander() const 
             { cout << "Quemande de la nourriture...\n"; }
     
     private:
        RACE wRace;
     };
     
     int main()
     {
    	 
        Chien Fido;
        Fido.wAge(2); //ici il y'a un problème
        Fido.Crier();
        Fido.RemuerQueue();
        cout << "Fido a " << Fido.LireAge() << " ans" << endl;
        return 0;
     }
    J'obtiens ce message d'erreur :

    'wAge' : cannot access protected member declared in class 'Mammifere'
    Je crée donc un objet de type Chien, je fais Fido.Age(2) et j'obtiens le message d'erreur ci-dessus.

    Je ne comprends pas pourquoi on peut mettre protected ou private si on ne peux pas utiliser les membres de la classe de base.

    Par contre, public j'ai compris que tous les éléments publics de la classe de base sont public à la classe fille et que les membres privés restent privés pour la classe fille.

    S'est Protected et Private que je ne comprends pas.

    Sincèrement, encore merci pour ton aide.

    beegees

  4. #4
    Membre régulier
    Inscrit en
    Avril 2007
    Messages
    82
    Détails du profil
    Informations forums :
    Inscription : Avril 2007
    Messages : 82
    Points : 72
    Points
    72
    Par défaut
    Ta variable age est récupérée par héritage de Mammifere , elle est privée dans chien . Quand tu es dans le code de méthodes(fonctions membres) d'une classe , tu peux accéder sans problème aux variables membres. Cependant là tu es dans le main, donc tu dois utiliser un "setter" ou un "getter" si tu veux respectivement donner une valeur à une variable ou récupérer la valeur d'une variable.

    Ici ton setter c'est : DefAge() et ton getter est LireAge()


    -> Fido.DefAge(2);

    En espérant t'avoir aidé

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Salut,

    J'ai l'impression que ton problème tient plus de la mauvaise compréhension des indicateurs de visibilité que de l'héritage.

    Quand tu n'est pas dans une méthode de ta classe (si tu es, par exemple, dans la fonction main ou que tu es dans une fonction qui ne fait pas partie de la classe), la seule chose à laquelle tu as accès en ce qui concerne ta classe, ce sont les membres et méthodes publiques (note cependant qu'il est relativement peu conseillé d'avoir des membres publiques).

    Quand tu déclares un membre ou une méthode protégé ("protected") cela revient à dire au compilateur que
    Le membre ou la méthode est invisible en dehors de la classe (par exemple dans la fonction main) mais reste accessible aux classes dérivées (et à celles qui dérivent de celles qui dérivent (je pourrais rajouter de nombreux "qui dérivent de celle") de celle-ci, s'il échoit)
    Quand tu déclares un membre ou une méthode privé ("private") cela revient à dire au compilateur que
    Le membre ou la méthode n'est accessible qu'aux méthodes de la classe.

    Il/elle n'est même pas accessible aux classes qui en dérivent.
    Dans le cadre d'un héritage, il y a éventuellement restriction dans la visibilité (un membre ou une méthode publique ou protégé à l'origine peut devenir privé ou protégé selon la visibilité de l'héritage) mais il n'y a absolument pas amélioration de la visibilité (avec un héritage publique, un membre ou une méthode privé reste privé par rapport à la classe de base et un membre ou une méthode protégé reste protégé).

    Il est possible d'affiner la visibilité d'un membre ou d'une méthode avec la directive using, mais il est fortement déconseillé de fournir une visibilité supérieure à celle d'origine.

    Ainsi, si tu as une classe de base prenant la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    class Base
    {
        public:
             /*...*/
            /*virtual */ void method();
            /*virtual */ void method2();
            /*virtual */ void method3();
    };
    et que tu veux avoir une classe dérivée qui expose method2 et méthod3 mais pas method parce qu'il n'est pas logique dans le cadre de la classe dérivée de fournir cette fonctionnalité, tu peux définir un héritage publique et diminuer la visibilité de method sous la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    class Derivee : public Base
    {
        private:
            using Base::Method;
    };
    Il serait admis (dans le sens que le compilateur ne se plaindra pas si tu le fais) d'améliorer la visibilité d'un membre ou d'une méthode par le même biais (de faire en sorte qu'une méthode privée dans la classe de base soit publique dans la classe dérivée), mais cela tiens, au mieux, d'un défaut de conception

    Enfin, il y a l'amitié, qui revient à dire au compilateur
    Je sais que tel et tel membre ou méthode est privé ou protégé, mais, à titre exceptionnel, j'autorise telle autre classe (qui n'a peut être aucun rapport d'héritage avec la classe) à y accéder
    Car autrement tu devrais systématiquement te restreindre à invoquer les méthodes publiques dans la classe amie.

    Il faut noter que l'amitié n'est ni héritée (ce n'est pas parce que tu es mon ami que tes enfants sont mes amis ou que tu es l'ami de mes parents), ni transitive (les amis de mes amis ne sont pas forcément mes amis), ni réciproque (ce n'est pas parce que je te donne accès à tout que je te demande d'en faire autant)

    Enfin, il y a tout le débat qui concerne la décision de permettre "à quelque chose d'externe" de modifier une valeur ou non, et de son corolaire concernant l'initialisation des valeurs (un chien ne devrait pas pouvoir passer du sexe male au sexe femelle, et le seul changement au niveau de son age serait peut être d'incrémenter la valeur le jour de son anniversaire )

    [EDIT]d'ailleurs, à bien y réfléchir, l'age devrait sans doute être calculé sur base de la date de naissance (non modifiable) et de la date actuelle...
    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

  6. #6
    Membre éprouvé
    Avatar de beegees
    Homme Profil pro
    Développeur Web
    Inscrit en
    Mars 2004
    Messages
    3 610
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2004
    Messages : 3 610
    Points : 1 277
    Points
    1 277
    Par défaut
    Salut Koala,

    Merci beaucoup pour ta réponse claire et précise.

    J'ai l'impression que ton problème tient plus de la mauvaise compréhension des indicateurs de visibilité que de l'héritage.
    Exactement, le problème vient de là car j'ai compris à quoi servait l'héritage et j'avoue que ça a l'air bien utile.

    Quand tu n'est pas dans une méthode de ta classe (si tu es, par exemple, dans la fonction main ou que tu es dans une fonction qui ne fait pas partie de la classe), la seule chose à laquelle tu as accès en ce qui concerne ta classe, ce sont les membres et méthodes publiques (note cependant qu'il est relativement peu conseillé d'avoir des membres publiques).
    Donc je peux créer un objet de type chien par exemple et utiliser dans le main ce qui est publique dans la classe de base mais ce qui est protected et private ne peut pas être utilisés.

    Par contre, je peux, quand s'est protected, utiliser un membre dans la classe de base ou dans la classe qui hérite de la classe de base, je me trompe ?

    Quand tu déclares un membre ou une méthode protégé ("protected") cela revient à dire au compilateur que

    Le membre ou la méthode est invisible en dehors de la classe (par exemple dans la fonction main) mais reste accessible aux classes dérivées (et à celles qui dérivent de celles qui dérivent (je pourrais rajouter de nombreux "qui dérivent de celle") de celle-ci, s'il échoit)
    Je présûme que tu entends pas "aux classes dérivées" les classes qui héritent de la classe de base ? La classe de base non comprise ?

    Quand tu déclares un membre ou une méthode privé ("private") cela revient à dire au compilateur que

    Le membre ou la méthode n'est accessible qu'aux méthodes de la classe.

    Il/elle n'est même pas accessible aux classes qui en dérivent.
    Pour ça s'est claire, merci, mais j'ai un exemple de classe ci-dessous (je vais l'appeler Classe A) qui hérite d'une manière privée d'une classe de base. Une classe en dessous de Classe A hérite avec une visibilité publique de Classe A, et s'est au départ de ce code que j'ai posé la question, je l'a met en bas de ce message pour que tu puisses t'en rendre compte par toi-même.

    Dans le cadre d'un héritage, il y a éventuellement restriction dans la visibilité (un membre ou une méthode publique ou protégé à l'origine peut devenir privé ou protégé selon la visibilité de l'héritage) mais il n'y a absolument pas amélioration de la visibilité (avec un héritage publique, un membre ou une méthode privé reste privé par rapport à la classe de base et un membre ou une méthode protégé reste protégé).
    Ca s'est une partie importe, merci.

    Il est possible d'affiner la visibilité d'un membre ou d'une méthode avec la directive using, mais il est fortement déconseillé de fournir une visibilité supérieure à celle d'origine.
    OK je suis ton conseil, je ne l'utiliserai pas.

    Enfin, il y a l'amitié, qui revient à dire au compilateur

    Citation:
    Je sais que tel et tel membre ou méthode est privé ou protégé, mais, à titre exceptionnel, j'autorise telle autre classe (qui n'a peut être aucun rapport d'héritage avec la classe) à y accéder

    Car autrement tu devrais systématiquement te restreindre à invoquer les méthodes publiques dans la classe amie.

    Il faut noter que l'amitié n'est ni héritée (ce n'est pas parce que tu es mon ami que tes enfants sont mes amis ou que tu es l'ami de mes parents), ni transitive (les amis de mes amis ne sont pas forcément mes amis), ni réciproque (ce n'est pas parce que je te donne accès à tout que je te demande d'en faire autant)
    Je connaissais l'amitié mais il y'a des choses qui ne m'avait pas fait tilt directement comme l'amitié ce n'est pas de l'héritage... donc merci, s'est important pour moi.

    Voici maintenant le code dont je te parlais là tout de suite :

    Le fichier header avec l'héritage :

    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
    #ifndef CHAINE_H
    #define CHAINE_H
     
    class CChaine
    {
    public:
    	CChaine();																// Constructeur par défaut
    	CChaine(const CChaine& Source);											// Constructeur par copie
    	CChaine(const char* UneChaine);											// Constructeur spécifique
    	~CChaine();																// Destructeur
     
    	const char*		Chaine() const;											// Accesseur du texte de la chaîne
    	bool			EstNull() const;										// Accesseur de test sur le texte (m_Chaine == NULL)
    	bool			EstVide() const;										// Accesseur de test sur le texte (m_Chaine == NULL) || (m_Chaine == "")
     
    	void			Vider();												// Modificateur permettant de supprimer le texte de la chaîne (on revient à NULL)
    	bool			Chaine(const char* UneChaine);							// Modificateur du texte de la chaîne
     
    private:
    	char*			m_Chaine;												// Membre contenant l'adresse du tableau de caractères alloué dynamiquement
    };
     
    class CChaineComposee : private CChaine
    {
    public:
    	CChaineComposee();														// Constructeur par défaut
    	CChaineComposee(const CChaineComposee& Source);							// Constructeur par copie
    	CChaineComposee(const char* UneChaine, char UnSeparateur);				// Constructeur spécifique
    	~CChaineComposee();														// Destructeur
     
    	long			NombreChamps() const;									// Accesseur du nombre de champs
    	const char*		Champs(long Indice) const;								// Accesseur d'un champ
     
    	bool			Definir(const char* UneChaine, char UnSeparateur);		// Modificateur permettant de modifier la chaîne et de générer le tableau des champs
     
    private:
    	bool			Decomposer(char UnSeparateur);							// Modificateur permettant de modifier la chaîne et de générer le tableau des champs
     
    private:
    	long			m_NbrChamps;
    	char**			m_Champs;
    };
     
    ////////////////////////////////
    // Class CChargeurFichierTexte//
    ////////////////////////////////
     
    class CChargeurFichierTexte : public CChaineComposee
     
    /*Donc en fait cette classe CChargeurFichierTexte à un moment donné ce qu'elle va contenir 
    comme information se sont les données d'une ligne mais déjà décomposée, sont but s'est 
    d'arriver à lire une ligne du fichier texte et de la décomposer automatiquement et donc en 
    servant des fonctionnalités publiques de la classe et bien on aura la possibilité de savoir 
    ce qu'il y'avait comme information sur la ligne (le nombre de champs et les valeurs  sous 
    forme de chaîne de caractère des différents champs) et ce qu'elle fournira en plus s'est 
    une méthode de chargement où on peut passer le nom du fichier et la fonction à appeler pour 
    pouvoir traiter les données d'une ligne puisque le but de la fonction charger s'est de :
     
    -	lire une ligne 
    -	d'appeler la fonction passer par celui qui utilise cette classe là
    -	et ensuite d'exécuter cette fonction
    -	et ensuite de passer à la lecture de la ligne suivante et ce jusqu'à la fin du fichier.
    */
    {
    public:
    	CChargeurFichierTexte();
    	~CChargeurFichierTexte();
     
    	bool			Charger(const char* NomFichier, char UnSeparateur, bool (* FctnTraiterLigne)(const CChargeurFichierTexte&, void*), void* Contexte);
     
    private:
    };
     
    #endif//CHAINE_H
    et le point cpp qui correspond à ce header :

    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
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    #include <BasicConsole.h>
    #include "chaine.h"
     
     
    ////////////////////
    // Classe CChaine //
    ////////////////////
     
    CChaine::CChaine() //constructeur par défaut
    :m_Chaine(NULL)
    {
    }
     
    CChaine::CChaine(const CChaine& Source) //constructeur par copie
    :m_Chaine(NULL)
    {
    	Chaine(Source.m_Chaine);
    }
     
    CChaine::CChaine(const char* UneChaine) //constructeur spécifique
    :m_Chaine(NULL)
    {
    	Chaine(UneChaine);
    }
     
    CChaine::~CChaine() //destructeur
    {
    	Vider();
    }
     
    void CChaine::Vider()
    {
    	if (m_Chaine != NULL)
    	{
    		free(m_Chaine);
    		m_Chaine = NULL;
    	}
    }
     
    bool CChaine::Chaine(const char* UneChaine)
    {
    	if (UneChaine == NULL) return false;
    	void* Nouveau = realloc(m_Chaine,(strlen(UneChaine)+1)*sizeof(char));
    	if (Nouveau == NULL) return false;
    	m_Chaine = (char*)Nouveau;
    	strcpy(m_Chaine,UneChaine);
    	return true;
    }
     
    const char* CChaine::Chaine() const
    {
    	return (m_Chaine != NULL) ? m_Chaine : "";
    }
     
    bool CChaine::EstNull() const
    {
    	return (m_Chaine == NULL);
    }
     
    bool CChaine::EstVide() const
    {
    	return (m_Chaine == NULL) || (m_Chaine[0] == 0);
    }
     
     
    ////////////////////////////
    // Classe CChaineComposee //
    ////////////////////////////
     
    CChaineComposee::CChaineComposee()
    :m_NbrChamps(0),m_Champs(NULL)
    {
    }
     
    CChaineComposee::CChaineComposee(const CChaineComposee& Source)
    :CChaine(Source),m_NbrChamps(0),m_Champs(NULL)
    {
    	if (Source.m_NbrChamps > 0)
    	{
    		m_Champs = (char**)malloc(Source.m_NbrChamps*sizeof(char*));
    		if (m_Champs != NULL)
    		{
    			m_NbrChamps = Source.m_NbrChamps;
    			for (long n=0; n < Source.m_NbrChamps; n++)
    			{
    				long PosRel = Source.m_Champs[n] - Source.m_Champs[0];
    				m_Champs[n] = ((char*)Chaine()) + PosRel;
    			}
    		}
    	}
    }
     
    CChaineComposee::CChaineComposee(const char* UneChaine, char UnSeparateur)
    :CChaine(UneChaine),m_NbrChamps(0),m_Champs(NULL)
    {
    	Decomposer(UnSeparateur);
    }
     
    CChaineComposee::~CChaineComposee()
    {
    	if (m_Champs) free(m_Champs);
    }
     
    long CChaineComposee::NombreChamps() const
    {
    	return m_NbrChamps;
    }
     
    const char* CChaineComposee::Champs(long Indice) const
    {
    	return ( (Indice >= 0) && (Indice < m_NbrChamps) ) ? m_Champs[Indice] : "";
    }
     
    bool CChaineComposee::Definir(const char* UneChaine, char UnSeparateur)
    {
    	if (!Chaine(UneChaine)) return false;
    	return Decomposer(UnSeparateur);
    }
     
    bool CChaineComposee::Decomposer(char UnSeparateur)
    {
    	m_NbrChamps = 0;
    	char* Texte = (char*)Chaine();
    	if (Texte == NULL) return false;
    	void* Nouveau = realloc(m_Champs,1*sizeof(char*));
    	if (Nouveau == NULL)
    	{
    		if (m_Champs)
    		{
    			free(m_Champs);
    			m_Champs = NULL;
    		}
    		return false;
    	}
    	m_Champs = (char**)Nouveau;
    	m_Champs[m_NbrChamps] = Texte;
    	m_NbrChamps++;
    	while (true)
    	{
    		char* Delimiteur = strchr(Texte,UnSeparateur);
    		if (Delimiteur == NULL) return true;
    		*Delimiteur = 0;
    		Texte = Delimiteur + 1;
    		void* Nouveau = realloc(m_Champs,(m_NbrChamps+1)*sizeof(char*));
    		if (Nouveau == NULL) return false;
    		m_Champs = (char**)Nouveau;
    		m_Champs[m_NbrChamps] = Texte;
    		m_NbrChamps++;
    	}
    }
     
     
    //////////////////////////////////
    // Classe CChargeurFichierTexte //
    //////////////////////////////////
     
    CChargeurFichierTexte::CChargeurFichierTexte()
    {
    }
     
    CChargeurFichierTexte::~CChargeurFichierTexte()
    {
    }
     
    bool CChargeurFichierTexte::Charger(const char* NomFichier, char UnSeparateur, bool (* FctnTraiterLigne)(const CChargeurFichierTexte&, void*), void* Contexte)
    {
    	const long		TailleLigne = 500;
    	char			Ligne[TailleLigne+1];
    	FILE*			Fichier;
     
    	if ( (NomFichier == NULL) || (*NomFichier == 0) ) return false;
    	Fichier = fopen(NomFichier,"rt");
    	while (fgets(Ligne,TailleLigne,Fichier) != NULL)
    	{
    		long i = strlen(Ligne);
    		if ( (i > 0) && (Ligne[i-1] == '\n') ) Ligne[i-1] = 0;
    		if (Definir(Ligne,'\t'))
    		{
    			if (!FctnTraiterLigne(*this,Contexte))
    			{
    				fclose(Fichier);
    				return false;
    			}
    		}
    	}
    	fclose(Fichier);
    	return true;
    }
    hier, un copain de classe m'a donné ces informations :

    tu n'as pas acces au priver mais tu a acces au public

    dans les fonctions

    regarde

    CChaineComposee::CChaineComposee(const CChaineComposee& Source)
    :CChaine(Source),m_NbrChamps ,m_Champs(NULL)
    {
    Chaine("hello");
    if(EstVide())
    printf("ee");
    if (Source.m_NbrChamps > 0)
    {
    m_Champs = (char**)malloc(Source.m_NbrChamps*sizeof(char*));
    if (m_Champs != NULL)
    {
    m_NbrChamps = Source.m_NbrChamps;
    for (long n=0; n < Source.m_NbrChamps; n++)
    {
    long PosRel = Source.m

    regarde les premieres lignes

    tu a acces au constructeur et au fonction de l'interieur de la classe

    donc je pense ( je pense beaucoup mais demande un truc officiel a la rentrée)

    privée en heritage

    met tout ce que contient la classe hériter en privée pour l'utilisateur*

    mais permet de se servir des attribut public dans les fonction de la chaine qui hérite

    *et bien les fonction public de CChaine ne sont pas utilisable dans le main par exemple
    *tu ne peut pas faire *CChaineComposee marco.Chaine("hello")
    Est-ce que tu comprends ce qu'il veut dire ?

    Encore merci pour ton aide vraiment très précieuse et tes réponses vraiment très claires.

    beegees

  7. #7
    Membre éprouvé
    Avatar de beegees
    Homme Profil pro
    Développeur Web
    Inscrit en
    Mars 2004
    Messages
    3 610
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2004
    Messages : 3 610
    Points : 1 277
    Points
    1 277
    Par défaut
    Citation Envoyé par Leole Voir le message
    Ta variable age est récupérée par héritage de Mammifere , elle est privée dans chien . Quand tu es dans le code de méthodes(fonctions membres) d'une classe , tu peux accéder sans problème aux variables membres. Cependant là tu es dans le main, donc tu dois utiliser un "setter" ou un "getter" si tu veux respectivement donner une valeur à une variable ou récupérer la valeur d'une variable.

    Ici ton setter c'est : DefAge() et ton getter est LireAge()


    -> Fido.DefAge(2);

    En espérant t'avoir aidé
    Bonjour Leole,

    Merci pour ta réponse qui m'a mis sur la piste ce matin.

    Ceci et la réponse de koala sont très complémentaires.

    Merci encore.

    beegees

  8. #8
    Membre régulier
    Inscrit en
    Avril 2007
    Messages
    82
    Détails du profil
    Informations forums :
    Inscription : Avril 2007
    Messages : 82
    Points : 72
    Points
    72
    Par défaut
    Pour savoir quoi mettre en public et quoi mettre en privé, tu dois réfléchir si celui qui a besoin de ta classe a besoin de savoir "ce qui se cache derrière". Il va utiliser des méthodes déclarées en publiques pour accéder à des variables membres privées. Cependant tu peux aussi déclarer des méthodes privées, elles seront seulement appelées à l'intérieur du code de fonctions de ta classe, l'utilisateur na pas besoin de savoir qu'elles existent.

    Sinon ce qu'a dit ton pote , j'ai pas trop pigé , c'est en sms ca me pique les yeux

  9. #9
    Membre éprouvé
    Avatar de beegees
    Homme Profil pro
    Développeur Web
    Inscrit en
    Mars 2004
    Messages
    3 610
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2004
    Messages : 3 610
    Points : 1 277
    Points
    1 277
    Par défaut
    Bonjour Leole,

    Merci pour ta réponse et pour ton dévouement.
    Pour savoir quoi mettre en public et quoi mettre en privé, tu dois éfléchir si celui qui a besoin de ta classe a besoin de savoir "ce qui se cache derrière". Il va utiliser des méthodes déclarées en publiques pour accéder à des variables membres privées. Cependant tu peux aussi déclarer des méthodes privées, elles seront seulement appelées à l'intérieur du code de fonctions de ta classe, l'utilisateur na pas besoin de savoir qu'elles existent.
    Je commence tout doucement à comprendre.

    Donc ma classe CChaineComposee hérite d'une manière privée de CChaine par ce qu'elle va travailler avec la classe CChaine sans avoir besoin de l'utilsateur (voir code ci-dessus stp) ?

    Sinon ce qu'a dit ton pote , j'ai pas trop pigé , c'est en sms ca me pique les yeux
    Tout à fait d'accord avec toi, j'ai pourtant amélioré ce qu'il dit.

    Merci encore.

    beegees

  10. #10
    Membre régulier
    Inscrit en
    Avril 2007
    Messages
    82
    Détails du profil
    Informations forums :
    Inscription : Avril 2007
    Messages : 82
    Points : 72
    Points
    72
    Par défaut
    Quand tu fais un héritage public : Les données publiques de la classe mère(base) restent publiques dans la classe fille (dérivée), ce qui est protected reste protected ( comme ça dans la classe petite fille, si tu fais encore un héritage publique sur la classe fille, tu peux encore l'utiliser ( elle sera encore protected) et ce qui est privé ,reste privé.)

    Quand tu fais un héritage privé :
    - classe mere -> fille : public -> privé
    protected -> privé
    privé -> privé

    Donc dans la classe fille qui hérite de maniere privée de la classe mere, tu ne pourras utiliser les fonctionnalités de la classe mere qu'a l'intérieur de la classe fille , et non en dehors de la classe ! ( ex : la fonction main() )

    edit : après tout dépend de comment tu veux utiliser ta classe .. personnelement je n'ai jamais eu à faire d'héritage privé mais bon je ne fais pas de c++ depuis longtemps non plus

  11. #11
    Membre éprouvé
    Avatar de beegees
    Homme Profil pro
    Développeur Web
    Inscrit en
    Mars 2004
    Messages
    3 610
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2004
    Messages : 3 610
    Points : 1 277
    Points
    1 277
    Par défaut
    Citation Envoyé par Leole Voir le message
    Quand tu fais un héritage public : Les données publiques de la classe mère(base) restent publiques dans la classe fille (dérivée), ce qui est protected reste protected ( comme ça dans la classe petite fille, si tu fais encore un héritage publique sur la classe fille, tu peux encore l'utiliser ( elle sera encore protected) et ce qui est privé ,reste privé.)

    Quand tu fais un héritage privé :
    - classe mere -> fille : public -> privé
    protected -> privé
    privé -> privé

    Donc dans la classe fille qui hérite de maniere privée de la classe mere, tu ne pourras utiliser les fonctionnalités de la classe mere qu'a l'intérieur de la classe fille , et non en dehors de la classe ! ( ex : la fonction main() )
    S'est génial, merci pour ta patience hors norme.

    ça devient de plus en plus claire tout ça.

    encore merci.

    beegees

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Citation Envoyé par beegees Voir le message
    Salut Koala,
    <snip>
    Exactement, le problème vient de là car j'ai compris à quoi servait l'héritage et j'avoue que ça a l'air bien utile.
    L'héritage est souvent défini de manière un peu incomplète comme une relation "est un".

    Autrement dit, l'héritage est à considérer quand tu te rend compte qu'une classe (dérivée) fournit (et éventuellement (ré)implémente) tous les services fournis par la classe de base, que la classe dérivée ne peut exister sans ces services, mais que tu envisage de considérer les instances de ta classe dérivée comme si c'était en réalité la classe de base (c'est ce qu'on appelle le polymorphisme)

    Ainsi, si tu envisage un chien, un chat, une girafe et un dauphin, tu considère que tous sont des mammifères.

    En effet, si tu retire "ce qui fait un mammifère", ton chien, ton chat, ta girafe et ton dauphin ne peuvent exister.

    Tu pourrais d'ailleurs compléter l'arbre d'héritage en déclarant les mammifères comme héritant de vertébré, ceux-ci héritant de "pluricellulaire", qui hériterait lui même de "etre_vivant" et en plaçant encore quelques classes intermédiaire entre la classe "mammifère" et les classes chien ("canidé"), chat ("félins"), girafe ("ongulés") ou dauphin ("cétacés").

    L'idée sous-jacente étant toujours de "spécialiser" certains comportements sans lesquels un chien (un mammifère, un canidé, un etre_vivant ou n'importe quelle classe pré citée) ne pourrait pas exister (se_reproduire est un comportement que l'on retrouve chez tous les êtres vivants mais qui prennent un sens différent pour un chien que pour une bactérie) et de rajouter un certain nombre de comportement particuliers.

    Donc je peux créer un objet de type chien par exemple et utiliser dans le main ce qui est publique dans la classe de base mais ce qui est protected et private ne peut pas être utilisés.
    Tu ne peux accéder, depuis une fonction externe à la classe qu'à ce qui est public pour la classe.

    Ainsi, dés le moment ou tu crée une instance de chien sous la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    /* mon chien s'appelle canelle, est une femelle de 11 ans, 
     * mesurant 60 cm au garrot et pesant 35 kg :D
     */ 
    Chien monchien("canelle",sFEMAL, 11, 60, 35);
    tu ne pourras accéder qu'aux méthodes publiques de la classe Chien.

    Par contre, dans les méthodes (fonctions membres) de la classe Chien, tu pourras utiliser tout ce qui est accessible depuis la classe, à savoir:
    1. les membres et méthodes publiques des classes de base
    2. les membres et méthodes protégés des classes de bases avec lesquelles un héritage publique ou protégé a été défini
    3. les membres et méthodes privés de la classe Chien

    Par contre, je peux, quand s'est protected, utiliser un membre dans la classe de base ou dans la classe qui hérite de la classe de base, je me trompe ?
    C'est bien ca... ainsi que dans la classe qui hérite (de manière publique ou protégée) de la classe qui hérite(de manière publique ou protégée) , de la classe qui hérite(de manière publique ou protégée) (je pourrais continuer longtemps comme cela) de la classe de base
    Je présûme que tu entends pas "aux classes dérivées" les classes qui héritent de la classe de base ? La classe de base non comprise ?
    les termes "classe fille", "classe héritière","classe descendante","classe dérivée" sont strictement synonymes et représente toujours la classe qui hérite d'une autre.

    Les termes "classe mere","classe de base","classe ancêtre" sont également synonymes et désignent toujours la classe "qui est héritée" par une classe dérivée

    Il faut juste noter que les termes "classe descendante" et "classe ancêtre" seront généralement utilisés pour indiquer qu'il peut y avoir plusieurs relations d'héritage entre la classe descendante et la classe ancêtre (ex: la classe chien est une classe descendante de la classe "etre_vivant", ou, à l'inverse, la classe "etre_vivant" est une classe ancêtre de la classe chien, parce qu'il y a plusieurs niveaux d'héritage entre les deux )

    Pour ça s'est claire, merci, mais j'ai un exemple de classe ci-dessous (je vais l'appeler Classe A) qui hérite d'une manière privée d'une classe de base. Une classe en dessous de Classe A hérite avec une visibilité publique de Classe A, et s'est au départ de ce code que j'ai posé la question, je l'a met en bas de ce message pour que tu puisses t'en rendre compte par toi-même.
    Je connaissais l'amitié mais il y'a des choses qui ne m'avait pas fait tilt directement comme l'amitié ce n'est pas de l'héritage... donc merci, s'est important pour moi.
    En fait, l'amitié est exactement similaire en programmation que dans la vie de tous les jours:
    • Tu n'es pas seulement ami avec les gens de ta famille
    • Ce n'est pas parce que tu fais confiance à quelqu'un que ce quelqu'un te fait confiance
    • Ce n'est pas parce que quelqu'un te fait confiance que tu a toute confiance en lui
    • les amis de tes amis ne sont pas forcément tes amis

    (à titre perso et dans la vie courante , je trouverais triste que la confiance ne soit pas partagée, mais en programmation, cela permet d'éviter les erreurs )

    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
    #ifndef CHAINE_H
    #define CHAINE_H
     
    class CChaine
    {
        public:
            CChaine(); // Constructeur par défaut
            CChaine(const CChaine& Source); // Constructeur par copie
            CChaine(const char* UneChaine);	// Constructeur spécifique
            ~CChaine(); // Destructeur
            const char* Chaine() const; // Accesseur du texte de la chaîne
            bool EstNull() const; // Accesseur de test sur le texte (m_Chaine == NULL)
            bool EstVide() const;// Accesseur de test sur le texte (m_Chaine == NULL) || (m_Chaine == "")
     
            void Vider(); // Modificateur permettant de supprimer le texte de la chaîne (on revient à NULL)
            bool Chaine(const char* UneChaine); // Modificateur du texte de la chaîne
     
        private:
            char* m_Chaine; // Membre contenant l'adresse du tableau de caractères alloué dynamiquement
    };
     
    class CChaineComposee : private CChaine
    {
        public:
            CChaineComposee(); // Constructeur par défaut
            CChaineComposee(const CChaineComposee& Source); // Constructeur par copie
            CChaineComposee(const char* UneChaine, char UnSeparateur);// Constructeur spécifique
            ~CChaineComposee();// Destructeur
     
            long NombreChamps() const;									// Accesseur du nombre de champs
    	const char*		Champs(long Indice) const;								// Accesseur d'un champ
     
    	bool			Definir(const char* UneChaine, char UnSeparateur);		// Modificateur permettant de modifier la chaîne et de générer le tableau des champs
     
    private:
    	bool			Decomposer(char UnSeparateur);							// Modificateur permettant de modifier la chaîne et de générer le tableau des champs
     
    private:
    	long			m_NbrChamps;
    	char**			m_Champs;
    };
     
    ////////////////////////////////
    // Class CChargeurFichierTexte//
    ////////////////////////////////
     
    class CChargeurFichierTexte : public CChaineComposee
     
    /*Donc en fait cette classe CChargeurFichierTexte à un moment donné ce qu'elle va contenir 
    comme information se sont les données d'une ligne mais déjà décomposée, sont but s'est 
    d'arriver à lire une ligne du fichier texte et de la décomposer automatiquement et donc en 
    servant des fonctionnalités publiques de la classe et bien on aura la possibilité de savoir 
    ce qu'il y'avait comme information sur la ligne (le nombre de champs et les valeurs  sous 
    forme de chaîne de caractère des différents champs) et ce qu'elle fournira en plus s'est 
    une méthode de chargement où on peut passer le nom du fichier et la fonction à appeler pour 
    pouvoir traiter les données d'une ligne puisque le but de la fonction charger s'est de :
     
    -	lire une ligne 
    -	d'appeler la fonction passer par celui qui utilise cette classe là
    -	et ensuite d'exécuter cette fonction
    -	et ensuite de passer à la lecture de la ligne suivante et ce jusqu'à la fin du fichier.
    */
    {
    public:
    	CChargeurFichierTexte();
    	~CChargeurFichierTexte();
     
    	bool			Charger(const char* NomFichier, char UnSeparateur, bool (* FctnTraiterLigne)(const CChargeurFichierTexte&, void*), void* Contexte);
     
    private:
    };
     
    #endif//CHAINE_H
    et le point cpp qui correspond à ce header :

    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
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    #include <BasicConsole.h>
    #include "chaine.h"
     
     
    ////////////////////
    // Classe CChaine //
    ////////////////////
     
    CChaine::CChaine() //constructeur par défaut
    :m_Chaine(NULL)
    {
    }
     
    CChaine::CChaine(const CChaine& Source) //constructeur par copie
    :m_Chaine(NULL)
    {
    	Chaine(Source.m_Chaine);
    }
     
    CChaine::CChaine(const char* UneChaine) //constructeur spécifique
    :m_Chaine(NULL)
    {
    	Chaine(UneChaine);
    }
     
    CChaine::~CChaine() //destructeur
    {
    	Vider();
    }
     
    void CChaine::Vider()
    {
    	if (m_Chaine != NULL)
    	{
    		free(m_Chaine);
    		m_Chaine = NULL;
    	}
    }
     
    bool CChaine::Chaine(const char* UneChaine)
    {
    	if (UneChaine == NULL) return false;
    	void* Nouveau = realloc(m_Chaine,(strlen(UneChaine)+1)*sizeof(char));
    	if (Nouveau == NULL) return false;
    	m_Chaine = (char*)Nouveau;
    	strcpy(m_Chaine,UneChaine);
    	return true;
    }
     
    const char* CChaine::Chaine() const
    {
    	return (m_Chaine != NULL) ? m_Chaine : "";
    }
     
    bool CChaine::EstNull() const
    {
    	return (m_Chaine == NULL);
    }
     
    bool CChaine::EstVide() const
    {
    	return (m_Chaine == NULL) || (m_Chaine[0] == 0);
    }
     
     
    ////////////////////////////
    // Classe CChaineComposee //
    ////////////////////////////
     
    CChaineComposee::CChaineComposee()
    :m_NbrChamps(0),m_Champs(NULL)
    {
    }
     
    CChaineComposee::CChaineComposee(const CChaineComposee& Source)
    :CChaine(Source),m_NbrChamps(0),m_Champs(NULL)
    {
    	if (Source.m_NbrChamps > 0)
    	{
    		m_Champs = (char**)malloc(Source.m_NbrChamps*sizeof(char*));
    		if (m_Champs != NULL)
    		{
    			m_NbrChamps = Source.m_NbrChamps;
    			for (long n=0; n < Source.m_NbrChamps; n++)
    			{
    				long PosRel = Source.m_Champs[n] - Source.m_Champs[0];
    				m_Champs[n] = ((char*)Chaine()) + PosRel;
    			}
    		}
    	}
    }
     
    CChaineComposee::CChaineComposee(const char* UneChaine, char UnSeparateur)
    :CChaine(UneChaine),m_NbrChamps(0),m_Champs(NULL)
    {
    	Decomposer(UnSeparateur);
    }
     
    CChaineComposee::~CChaineComposee()
    {
    	if (m_Champs) free(m_Champs);
    }
     
    long CChaineComposee::NombreChamps() const
    {
    	return m_NbrChamps;
    }
     
    const char* CChaineComposee::Champs(long Indice) const
    {
    	return ( (Indice >= 0) && (Indice < m_NbrChamps) ) ? m_Champs[Indice] : "";
    }
     
    bool CChaineComposee::Definir(const char* UneChaine, char UnSeparateur)
    {
    	if (!Chaine(UneChaine)) return false;
    	return Decomposer(UnSeparateur);
    }
     
    bool CChaineComposee::Decomposer(char UnSeparateur)
    {
    	m_NbrChamps = 0;
    	char* Texte = (char*)Chaine();
    	if (Texte == NULL) return false;
    	void* Nouveau = realloc(m_Champs,1*sizeof(char*));
    	if (Nouveau == NULL)
    	{
    		if (m_Champs)
    		{
    			free(m_Champs);
    			m_Champs = NULL;
    		}
    		return false;
    	}
    	m_Champs = (char**)Nouveau;
    	m_Champs[m_NbrChamps] = Texte;
    	m_NbrChamps++;
    	while (true)
    	{
    		char* Delimiteur = strchr(Texte,UnSeparateur);
    		if (Delimiteur == NULL) return true;
    		*Delimiteur = 0;
    		Texte = Delimiteur + 1;
    		void* Nouveau = realloc(m_Champs,(m_NbrChamps+1)*sizeof(char*));
    		if (Nouveau == NULL) return false;
    		m_Champs = (char**)Nouveau;
    		m_Champs[m_NbrChamps] = Texte;
    		m_NbrChamps++;
    	}
    }
     
     
    //////////////////////////////////
    // Classe CChargeurFichierTexte //
    //////////////////////////////////
     
    CChargeurFichierTexte::CChargeurFichierTexte()
    {
    }
     
    CChargeurFichierTexte::~CChargeurFichierTexte()
    {
    }
     
    bool CChargeurFichierTexte::Charger(const char* NomFichier, char UnSeparateur, bool (* FctnTraiterLigne)(const CChargeurFichierTexte&, void*), void* Contexte)
    {
    	const long		TailleLigne = 500;
    	char			Ligne[TailleLigne+1];
    	FILE*			Fichier;
     
    	if ( (NomFichier == NULL) || (*NomFichier == 0) ) return false;
    	Fichier = fopen(NomFichier,"rt");
    	while (fgets(Ligne,TailleLigne,Fichier) != NULL)
    	{
    		long i = strlen(Ligne);
    		if ( (i > 0) && (Ligne[i-1] == '\n') ) Ligne[i-1] = 0;
    		if (Definir(Ligne,'\t'))
    		{
    			if (!FctnTraiterLigne(*this,Contexte))
    			{
    				fclose(Fichier);
    				return false;
    			}
    		}
    	}
    	fclose(Fichier);
    	return true;
    }
    hier, un copain de classe m'a donné ces informations :



    Est-ce que tu comprends ce qu'il veut dire ?

    Encore merci pour ton aide vraiment très précieuse et tes réponses vraiment très claires.

    beegees
    Quelques petits conseils en passant:
    • place tes commentaires de préférence avant le code auquel ils se rapportent (ou tout de suite après sur la même ligne, avec un minimum d'espace entre le code et le commentaire)
    • Si les commentaires sont sans doute la seule chose dont l'excès ne nuit pas en programmation, leur réel attrait est de fournir un moyen de comprendre plus facilement ce que le code peut laisser dans l'ombre.

      Je ne vois aucune raison pour t'interdire de commenter systématiquement les déclarations des différents membres et méthodes de tes classes, mais, comme tu choisi des noms explicites, crois tu vraiment que les commentaires soient impératifs
    • Il n'est pas forcément d'usage d'aligner les intérieurs de plusieurs lignes de code entre elles en C++ (je sais que c'est souvent apprécié en COBOL, par exemple, mais c'est clairement inutile en C++ )
    • préfères les espaces aux tabulations dans ton code: cela permet de s'assurer que la "mise en forme" (qui n'importe en définitive qu'à l'utilisateur) restera identique quels que puissent être les réglage de l'éditeur de texte

    De manière plus générale, je peux concevoir qu'une "chaine composée" soit une chaine normale, et donc, concevoir l'héritage.

    Par contre, crois tu vraiment utile que ta classe CChargeurFichierTexte soit déclarée comme dérivant de ta chaine composée

    L'un des principes sacrosaints de la programmation est la délégation des responsabilités.

    En l'espèce, je trouve que cette classe ne devrait avoir qu'une seule responsabilité: celle de permettre de récupérer une chaine composée au départ d'un fichier... mais, en aucun cas celle d'être la chaine composée.

    La décomposition de la chaine composée devrait revenir... à la chaine composée elle-même, et non à la classe qui la récupère du fichier

    Au final, je me dis (mais bon, il faudrait voir tes specs) que chaine composée peut hériter de chaine, mais que le chargeur de fichier devrait fournir un aglomérat de chaines composées

    En passant, juste comme cela, sais tu qu'il existe une classe particulière en C++, nommée string (disponible par inclusion du fichier d'en tete <string> dans l'espace de noms std) qui fournit déjà une série de méthodes propres à la gestion des chaines de caractères
    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

  13. #13
    Membre éprouvé
    Avatar de beegees
    Homme Profil pro
    Développeur Web
    Inscrit en
    Mars 2004
    Messages
    3 610
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : Enseignement

    Informations forums :
    Inscription : Mars 2004
    Messages : 3 610
    Points : 1 277
    Points
    1 277
    Par défaut
    Salut Koala

    Un tout GRAND merci pour ton message que je vais m'empresser d'imprimer et de lire dans le train.

    Je reviens très vite avec mes commentaires.

    Voilà j'ai lu ta réponse.

    Ben comme d'hab elle est hyper précise et hyper bien expliquée.

    Je commence à mieux me débrouiller maintenant et ça s'est entre autre grâce à toi, je t'en remercie mille fois.

    Sache que tes messages accompagneront mes notes personnelles lors de mon examen de C++.

    Merci encore pour tout.

    beegees

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

Discussions similaires

  1. Question sur l'héritage multiple
    Par paparasta dans le forum C++
    Réponses: 14
    Dernier message: 13/08/2010, 21h14
  2. Question sur l'héritage (débutant en C++)
    Par beegees dans le forum C++
    Réponses: 19
    Dernier message: 30/03/2008, 14h45
  3. petite question sur l'héritage et les cast
    Par baedal dans le forum Langage
    Réponses: 3
    Dernier message: 29/02/2008, 00h48
  4. Questions sur l'héritage dans Matisse
    Par Cassios dans le forum NetBeans
    Réponses: 8
    Dernier message: 14/03/2007, 23h23
  5. Question sur l'héritage
    Par the big ben 5 dans le forum Delphi
    Réponses: 28
    Dernier message: 06/06/2006, 17h27

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