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 :

Encapsulation pour donner des accès minimum à chaque classe


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé Avatar de Ekinoks
    Profil pro
    Étudiant
    Inscrit en
    Novembre 2003
    Messages
    687
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2003
    Messages : 687
    Par défaut Encapsulation pour donner des accès minimum à chaque classe
    Salut !

    J'ai un problème d'encapsulation, je n'arrive pas à trouver de moyen pour que chaque classe n'est accès qu'as ce qu'il a besoin.

    Voici le 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
     
    // Charger de s'occuper de "type value_" (création / suppression / stockage)
    class Value
    {
    	public :
    		Value(type value) : value_(value) {}
     
    	private :
    		type value_;
    };
     
    // classe mere qui sera hérité par beaucoup de classe fils
    class Mere
    {
    	public :
    		Mere(type t) : v_(t)
    		{
    		}
    		//...
     
    	private :
    		Value v_;
    		//...
    };
     
    // Cette classe et ses descendants doivent être les seul qui on le droit d'accéder à "Value::value_"
    class SeulClassQuiUtiliseValue
    {
    	public :
    		void getValue(A &a)
    		{
    			// besoin d'utiliser A.v.value_
    		}
    };
    Quelque solution :
    1) Créer des accesseurs de "v_" dans "Mere" et de "value_" dans "Value".
    Problème : Toute les classe qui hérite de la classe "Mere" auront un moyen d'accéder également a "value_" en utilisant les accésseurs.

    2) Mettre SeulClassQuiUtiliseValue::getValue(A &a) comme amie de "Mere" et de "Value"
    Problème : Cette méthode "getValue" auras un accès complet au membre privé de "Mere" alors que seulement "v_" nous intéresse.

    3) Créer un accésseur de "V_" dans classe "Mere" et mettre SeulClassQuiUtiliseValue::getValue(A &a) comme amie de "Value".
    Problème : Toute les classe qui hérite de la classe "Mere" auront accès a "v_".
    Bien qu'ils ne puissent rien en faire directement car pas accès a "value_",
    on pourrais être tenté d'utiliser ce "v_" comme argument pour une méthode de "SeulClassQuiUtiliseValue" (ou une classe dérivé).
    Ainsi, la classe Value jouerait un rôle dans les classe dérivé de la classe "Mere" alors quel ne devrais pas.


    Les trois solutions au quel j'ai pensé présente toutes des inconvenants...
    Existerait il d'autre solutions pour résoudre ce problème ?
    Et si aucune autre solution existe, quel serais la meilleur ?

    Merci pour votre aide.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Salut,

    En fait, il y a un mix de tout à faire:
    1. Rendre la classe Value non copiable et non assignable ( == déclarer sans les définir le constructeur par copie et l'opérateur d'affectation dans l'accessibilité private)
    2. Déclarer le membre de type value uniquement dans la classe qui en a besoin (dans l'accessibilité priavate)
    3. Déclarer la classe qui a besoin de Value::value_ (ou une de ses méthodes private) amie de la classe Value

    Cela prendrait la forme de
    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
    class Value; // déclaration anticipée de la classe, pour qu'elle soit connue
                 // lorsque le compilateur la rencontre dans ClassQuiUitiliseValue
    class Mere
    {
        /*aucune référence à la classe Value ici */
        public:
            Mere(){}
            virtual ~Mere(){}
            /* méthodes publiques  */
        private:
            /* membres et méthodes privées */
    };
    class ClassQuiUitiliseValue : public Mere
    {
        public:
            ClasseQuiUtiliseValue( type v): val_(v){}
            virtual ~ClasseQuiUtiliseValue(){}
            /* les méthodes qui vont bien et qui peuvent être publiques */
        private:
            /* Seule ClasseQuiUtiliseValue pourra accéder à cette méthode
             * mais son implémentation doit être déportée après la définition
             * réelle de la classe Value 
             */
            /* inline */ le_type_qui_va_bien function();
            Value val_;
    };
    class Value
    {
        public : 
            /* il pourrait être private... mais donnons nous l'occasion de
             * quand meme la construire
             */
            Value(type value_):value_(value_){}
            /* d'office public, sinon nous aurons un problème */
            ~Value(){}
        private:
            type value_;
            /*La copie est interdite  */
            Value(const Value&);
            /* l'affectation itou */
            Value operaor= (const Value&);
            friend le_type_qui_va_bien ClasseQuiUtiliseValue::function();
    };
    /*inline */ le_type_qui_va_bien ClasseQuiUtiliseValue::function()
    {
        /* ce qu'il faut faire, en pouvant très bien envisager un code proche de*/
        type temp = val_::value_;
    }
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Pour te permettre d'en comprendre un peu plus sur l'amitié...

    Si tu déclare une classe amie, il faut savoir que l'amitié n'est ni transitive, ni réciproque, ni héritée (et c'est ce dernier terme qui nous intéresse).

    Cela signifie que seules les méthodes qui peuvent être utilisées en faisant passer une instance d'une autre classe pour une instance de la classe déclarée amie pourront envisager d'accéder aux membres et méthodes non publiques.

    En outre, une classe dérivée n'a acces qu'aux membres et méthodes publiques ou protégés (mais en aucun privés) de la classe dont elle dérive.

    Ainsi, si tu as un code proche de
    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 Mere
    {
        public:
            /*...*/
            void foo();
            type1 publicMember;
        protected:
            void bar();
            type2 protectedMember;
        private:
            void privateFoo();
            type3 privateMember;
    };
    class Derivee : public Mere
    {
        /*...*/
    };
    la classe Derivee ne pourra accéder qu'à foo, bar, publicMember et protectedMember...

    Si même, tu en venais à rendre (par exemple) foo virtuelle et à la spécialiser (dans une optique de polymorphisme) dans dérivée, tu devrais passer par Mere::foo pour avoir réellement acces aux membres non public de la classe qui déclare mère amie.

    Ainsi, un code proche de
    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
    class Value
    {
        public:
            friend class Mere;
            Value(int i):i(i){}
            ~Value(){}
        protected:
        private:
            int i;
    };
     
    class Mere
    {
        public:
    	Mere(const Value& v):v(v){}
            virtual ~Mere(){}
            virtual void foo(){cout<<"dans mere "<< v.i<<endl;}
        protected:
            virtual void bar(){}
            Value v;
        private:
     
    };
    class Fille : public Mere
    {
        public:
            Fille(const Value& v):Mere(v){}
            virtual ~Fille(){}
            virtual void foo()
            {
                cout<<"dans fille "<< v.i<<endl; //refusé
                /* par contre ce qui suit serait accepté
                 * cout<<"Fille appelle Mere::foo ";
                 * Mere::foo();
                 */                          
            }
        protected:
            virtual void bar(){}
        private:
     
    };
    refusera de compiler au prétexte que v::i est privé dans le contexte de Fille::foo (bien quelle puisse accéder à v, étant donné que le membre est protégé)...

    Si, en plus, tu venais à placer v (ou la fonction qui doit y accéder) dans l'accessibilité privée de Mere, Fille ne pourrait même pas accéder ni à v ni à la fonction qui tente d'y accéder (et cette fonction ne pourrait d'ailleurs pas être spécialisée dans la classe dérivée)
    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

  4. #4
    Membre éclairé Avatar de Ekinoks
    Profil pro
    Étudiant
    Inscrit en
    Novembre 2003
    Messages
    687
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2003
    Messages : 687
    Par défaut
    Un grand merci koala pour ta réponse =)

    Citation Envoyé par koala01 Voir le message
    1. Rendre la classe Value non copiable et non assignable ( == déclarer sans les définir le constructeur par copie et l'opérateur d'affectation dans l'accessibilité private)
    2. Déclarer le membre de type value uniquement dans la classe qui en a besoin (dans l'accessibilité priavate)
    3. Déclarer la classe qui a besoin de Value::value_ (ou une de ses méthodes private) amie de la classe Value
    2> Ha oui, effectivement, en modifiant un peu ma conception pour faire en sorte que ce soit "ClassQuiUitiliseValue" qui stock également "Value" ça arrange pas mal de chose ! =)
    3 > Mais, du coup, si on arrive à mettre en place le second point, ça ne sert plus à rien de protéger d'avantage la classe "Value" non ? vue que SEUL "ClassQuiUitiliseValue", stock et utilise "Value".
    1> Pareil que pour le points 3, si on arrive à mettre en place le point 2, je n'arrive pas à voir à quoi sert cette sécurité supplémentaire ?

    Une dernière question, si jamais, la conception fait qu'on ne puisse pas utiliser le point (2), comment faire ? (si il existe des cas ou on ne puisse pas appliquer le point (2) ?)


    Merci pour votre aide.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Il est vrai que l'utilité du point 1 est discutable, mais c'est surtout pour éviter la tentation d'écrire une méthode dans une autre classe qui tenterait de créer une instance de Value (c'est d'ailleurs la raison pour laquelle je verrais bien placer le constructeur en accessibilité privée, ainsi, seule les classes déclarées amies pourront créer une instance de Value )

    Le point 3 est obligatoire, si tu veux que la classe qui utilise la classe Value puisse... accéder à la valeur du membre (car, si tu crées un accesseur pour ce membre, tu permet à n'importe quelle classe d'y accéder )
    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 éclairé Avatar de Ekinoks
    Profil pro
    Étudiant
    Inscrit en
    Novembre 2003
    Messages
    687
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2003
    Messages : 687
    Par défaut
    Ha ok, ca y est je crois que j'ai compris, en faite tu te place au niveau de la classe "Value" et pas au niveau du projet dans sa globalité.

    Au lieu de dire : "C'est à la classes qui contient 'Value' que revient la responsabilité de bien utiliser m'utiliser".
    Tu dit : "C'est à la classes 'Value' de dire qui à le droit de m'utiliser (qui a la responsabilité de bien m'utiliser)".


    C'est bien ça ?

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    C'est effectivement quelque chose dans le genre...

    Mais, à vrai dire, je n'ai pas énormément le choix, étant donné que tu souhaite ne pas placer d'accesseur sur les membre de Value... il faut donc bien décider à un moment de qui aura la responsabilité d'autoriser (ou non) l'accès aux données
    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

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

Discussions similaires

  1. htaccess et php ( pour donner l'accès a un dossier)
    Par paterson dans le forum Langage
    Réponses: 1
    Dernier message: 07/03/2012, 14h07
  2. Des bénévoles pour donner des cours dans les langues : Français, Anglais et Arabe
    Par witch dans le forum La taverne du Club : Humour et divers
    Réponses: 15
    Dernier message: 24/02/2012, 23h47
  3. [FPDF] Quelle classe pour produire des PDF simples ?
    Par boteha dans le forum Bibliothèques et frameworks
    Réponses: 6
    Dernier message: 03/11/2005, 22h55
  4. Classe pour generer des logs
    Par freddyboy dans le forum MFC
    Réponses: 9
    Dernier message: 13/07/2005, 12h54
  5. Réponses: 2
    Dernier message: 19/01/2004, 12h19

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