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 :

Mutateur et accesseur sur énumération


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé Avatar de stallaf
    Homme Profil pro
    Inscrit en
    Novembre 2007
    Messages
    79
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2007
    Messages : 79
    Par défaut Mutateur et accesseur sur énumération
    Bonjour à tous et à toutes

    J'ai un type non reconnu sans savoir comment pourquoi. Voici le code et les erreurs correspondantes :
    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
     
    class UserSingleton : public Singleton<UserSingleton> {
     
    friend class Singleton<UserSingleton>;
     
    public:
        	void set_name( const QString &newName ) { this->name = newName; }
        	void set_pass( const QString &newPass ) { this->pass = newPass; }
     
            void set_rights( rights newRights ) {  //  ‘rights’ has not been declared 
        		e_rights rights;
        		rights = newRights; // invalid conversion from ‘int’ to ‘UserSingleton::e_rights’ 
    		}
     
        	inline const QString get_name() const { return this->name; }
        	inline const QString get_pass() const { return this->pass; }
        	inline const e_rights get_rights() const { return  this->rights; }
    /* ‘e_rights’ does not name a type */
     
    private:
        	UserSingleton();
        	~UserSingleton();
        	static UserSingleton * userInstance;
        	QString name;
        	QString pass;
        	typedef enum {
        	    root,
        	    settings,
        	    remove,
        	    create,
        	    modify,
        	    print,
        	    search,
        	    none
        	} e_rights;
        	e_rights rights;
    };
    Pouvez-vous me renseigner ? Merci d'avance.

  2. #2
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    Salut,
    L'énumération n'est pas définie au moment de son utilisation et il y a un imbroglio entre le type et les noms de variables dans set_rights :
    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
    class UserSingleton : public Singleton<UserSingleton> {
     
    friend class Singleton<UserSingleton>;
    enum e_rights{
        root,
        settings,
        remove,
        create,
        modify,
        print,
        search,
        none
    } ;
     
    public:
        	void set_name( const QString &newName ) { this->name = newName; }
        	void set_pass( const QString &newPass ) { this->pass = newPass; }
     
            void set_rights( e_rights newRights ) {  //  ‘rights’ has not been declared
        		//e_rights rights;
        		rights = newRights; // invalid conversion from ‘int’ to ‘UserSingleton::e_rights’
    		}
     
        	inline const QString get_name() const { return this->name; }
        	inline const QString get_pass() const { return this->pass; }
        	inline const e_rights get_rights() const { return  this->rights; }
     
    private:
        	UserSingleton();
        	~UserSingleton();
        	static UserSingleton * userInstance;
        	QString name;
        	QString pass;
        	e_rights rights;
    };

  3. #3
    Membre confirmé Avatar de stallaf
    Homme Profil pro
    Inscrit en
    Novembre 2007
    Messages
    79
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2007
    Messages : 79
    Par défaut
    Ouarffff
    Il faut que je fasse une pause, je ne vois plus rien.
    Merci

  4. #4
    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,

    De plus, pour que les valeurs énumérées soient utilisables depuis l'extérieur (par exemple pour que tu puisse déterminer les droits de quelqu'un, ou tester la valeur renvoyée par get_rights ), il faut que l'énumération soit... publique...

    Ceci dit, il ne me semble pas vraiment opportun ni de créer un singleton pour gérer l'utilisateur, ni de proposer les mutateurs sur le nom, le mot de passe ou les droits.

    D'ailleurs, à bien y réfléchir, il ne me semble pas vraiment opportun de permettre à tout le monde de récupérer le mot de passe de l'utilisateur depuis n'importe où, en exposant un accesseur sur celui-ci

    Comme ces deux dernières phrases sont un peu lacunaires, autant te donner quelques explications et quelques pistes que tu pourrais explorer pour corriger ces "problèmes"

    Le singleton est souvent considéré, à juste titre, comme un "anti pattern", dans le sens où il y a souvent moyen de s'en passer et où les cas dans lesquels il est absolument indispensable représentent une grosse minorité des cas où l'on serait tenté d'y recourir.

    Le plus souvent, le meilleur moyen de s'assurer qu'il n'y a qu'une seule instance d'un objet qui est créé est encore... d'empêcher d'en créer plusieurs

    Si tu veux l'assurance qu'il n'y aura jamais qu'un seul utilisateur connecté à un moment donné, le mieux est encore de faire en sorte qu'il soit impossible à un utilisateur de se connecter tant que celui qui est connecté à un instant T ne s'est pas déconnecté

    De plus, les cas où tu devra effectivement disposer d'informations concernant l'utilisateur sont, malgré tout, *relativement* restreints et clairement identifiés.

    Il est dont tout à fait inutile de vouloir permettre un accès à l'utilisateur depuis n'importe où, et il "suffit" de transmettre celui-ci "quand cela se justifie"

    En ce qui concerne l'opportunité de proposer un mutateur sur le login, sur le mot de passe et sur les droits accordés:

    Un utilisateur a, typiquement, valeur d'entité: si tu change le login, le mot de passe ou les droits accordés, tu as... littéralement un autre utilisateur

    De ce fait, le mieux est peut être carrément de... définir ces informations directement à la création de l'utilisateur, idéalement, en ne permettant qu'à une seule classe de créer un utilisateur, et de ne pas donner l'occasion de les modifier une fois qu'ils ont été détfinis

    En ce qui concerne pour finir l'opportunité de fournir un accesseur sur le mot de passe:

    Typiquement, le mot de passe n'est vérifié... que lors de la connexion d'un utilisateur, à l'aide d'un "système externe" (une table de base de données, un fichier texte ou dans un format quelconque, ...) dans lequel il ne devrait même pas apparaitre en clair.

    Le système externe devrait, idéalement, assurer la persistance de cette info sous la forme d'une somme MD5 par exemple ou de tout autre somme de contrôle "sécurisante" (de la série des SHA et autres).

    Mais, quel que soit le système de cryptage envisagé, et surtout si le mot de passe est disponible en clair, il est largement préférable d'éviter à tout à chacun d'y accéder, ne serait-ce que parce qu'il deviendrait alors beaucoup trop facile d'arriver à créer une "collision" (en gros: de trouver un mot de passe ayant la même somme de contrôle).

    Si donc, tu tiens absolument à ce que l'utilisateur "trimbale" avec lui le mot de passe (et tu auras compris que je considère déjà cela comme une très mauvaise idée ), tu dois veiller à ce qu'il y ait un minimum d'endroits d'où il soit possible d'y accéder.

    Cela implique que, si tu as *réellement besoin* de permettre une comparaison entre le mot de passe d'un utilisateur et un mot de passe récupéré "par ailleurs", cela devrait se faire en passant par une fonction membre nommée, pour l'exemple, samePassWord et prenant le mot de passe à comparer en paramètre.

    Au final, ta classe utilisateur pourrait ressembler à quelque chose comme:
    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
    class User
    {
        /* on considère qu'il faut passer par UserManager pour
         * se connecter et se déconnecter ;)
         *
         * Ce sera la seule classe susceptible de créer un utilisateur :D
         */
        friend class UserManager;
        public:
            /* il est sans doute utile de permettre aux gens de tester les droits
             * d'un utilisateur :D... C'est pour cela que l'énumération est publique
             */
            enum e_rights { // au fait, le typedef est inutile en C++ :D
        	    root,
        	    settings,
        	    remove,
        	    create,
        	    modify,
        	    print,
        	    search,
        	    none
        	};
            QString const & login() const{return login_;}
            /* on permet à tout le monde de récupérer les droits de l'utilisateur
             * (note que cela devrait être murement réfléchi :D)
             */
            e_rights rights() const{return rigths_;}
            /* on permet de tester si un mot de passe correspond à celui de 
             * l'utilisateur
             */
            bool samePassWord(QString const & s) const
            {
                QString converted=MD5(s);// si mot de passe crypté, à adapter :D
                return converted==pass_;
            }
        private:
            /* constructeur et destructeur ne seront utilisés que par
             * UserManager
             */
            User(QString const & u, QString const & p, e_rights r ):
                login_(u),pass_(p),rights_(r){}
            ~User(){}
            /* C++1x permet de faire autrement, en attendant, on interdit
             * la copie et l'affectation en déclarant le constructeur par
             * copie et l'opérateur d'affectation SANS LES DEFINIR
             * dans l'accessibilité privée
             */
            User(User const &);
            User & operator=(User const &);
            /* les membres qui vont bien */
            QString login_;
            QString pass_;
            e_rights rights_;
    };
    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 confirmé Avatar de stallaf
    Homme Profil pro
    Inscrit en
    Novembre 2007
    Messages
    79
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2007
    Messages : 79
    Par défaut
    Merci koala01 pour toutes ces informations

    En fait, pour le moment j'expérimente et tâtonne pas mal. Voilà pourquoi l'approche est mauvaise. Je me serais bien appuyé sur quelque chose d'existant quelque part mais j'aime la découverte

    Revenons sur le fonds et apportons quelques explications Après étude des besoins, cas d'utilisation... il me faut gérer authentification et droits. Quatre groupes d'utilisateurs sont crées et je choisis de faire correspondre les droits à une liste d'actions autorisés pour chaque groupe (qui peut le plus peut le moins).

    J'utilise une base de donnée mysql et une table ou mes passes sont enregistrés en SHA1. J'ouvre l'application, vérifie la connexion puis demande login et mot de passe pour attribution des droits.

    Je pensais donc vérifier les droits avant chaque action en nécessitant et il me faut l'utilisateur accessible partout. Maintenant, le changement d'utilisateur doit être possible sans fermer l'application (fermeture de session - nouvelle connexion).

    L'objet unique me paraît bien, en effet, avec destruction de l'ancien et création d'un nouveau. Aucune modification autorisée sur cet objet, seul un accesseur pour les droits semblent bien.

    Voilà pourquoi je partais sur un singleton pensant que cela correspondait pas mal à la problématique.
    Comment ferait un programmeur expérimenté ? Quel est la moins mauvaise des solutions ? Merci pour vos conseils avisés.

  6. #6
    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
    Ben, je commencerais par clairement déléguer les responsabilités...

    L'utilisateur n'a qu'une responsabilité: indiquer à l'application quels sont ses droits (et éventuellement permettre à l'application de savoir qui est connecté )

    La classe User serait donc 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
    class User
    {
        friend class UserManager;
        public:
            /* j'ai inversé l'ordre des droits, car les valeurs sont incrémentales
             * dans une énumération... tu peux donc "simplement" tester si
             * le droit d'utilisateur est... plus grand ou égal à celui qui est 
             * nécessaire :D
             */
            enum e_rights { 
        	    none,        
        	    search,
        	    print,
        	    modify,
        	    create,
        	    remove,
        	    settings,
        	    root
        	};
            QString const & login() const{return login_;}
            e_rights rights() const{return rigths_;}
        private:
            /* constructeur et destructeur ne seront utilisés que par
             * UserManager
             */
            User(QString const & u,e_rights r ):
                login_(u),rights_(r){}
            ~User(){}
            /* cf le message précédent ;) */
            User(User const &);
            User & operator=(User const &);
            /* les membres qui vont bien */
            QString login_;
            e_rights rights_;
    };
    J'aurais un gestionnaire de connexion à MySQL qui se contente de... gérer la connexion (créer / recréer / détruire la connexion au serveur MySQL) et de la transmettre connexion "à qui de droit" (le gestionnaire d'utilisateur et le gestionnaire de requêtes, par exemple):
    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
    class ConnectionManager
    {
            /* Comme tu travailles avec Qt, on n'autorise la création d'une 
             * instance que depuis la fenêtre principale...
             * Par facilité je choisi qu'elle s'appelle MyGUI (faudra adapter :D) 
             */
        friend class MyGUI;
        public:
            bool connected() const
            {
                // vérifie si la connexion existe et est active 
                // on "dit que" la connexion dispose d'une fonction active :D
                return (conn_!=NULL && conn->active());
            }
            // demande de se connecter au serveur
            // renvoie la connexion active 
            Connection * Connect()
            {
                // si on est déjà connecté, on renvoie la connexion
                if(connected())
                    return conn_;
                // si la connexion existe mais n'est pas active, on la recrée
                if(conn_)
                {
                    delete conn_;
                    conn_ = new Connection(server_);
               }
               return conn_;
            }
            // se déconnecte du serveur MySQL
            void disconnect()
            {
                delete conn_;
                conn_=NULL;
            }
            /* si c'est intéressant, on permet de récupérer le nom du serveur
             * et de le modifier
             */
            QString const & serverName() const{return server_;}
            void changeServer(QString const & newserver)
            {
                /* pour pouvoir le faire, on procède à la déconnexion automatique
                 */
                disconnect();
                server_=newserver;
            }
        private:
            ConnectionManager(QString const & ser):server_(ser){}
            ~ConnectionManager(){disconnect();}
            // copie et affectation interdites 
            ConnectionManager(ConnectionManager const &);
            ConnectionManager& operator=(ConnectionManager const &);
            QString server;
            Connection * conn_;
    };
    J'aurais sans doute un gestionnaire de requêtes, qui place les nouvelles requêtes dans une file, qui les envoie au serveur (via le gestionnaire de connexions) et qui place le résultat dans une autre file.

    Ce gestionnaire de requête serait "alimenté" en requêtes par... une fabrique à requêtes, et on laisserait à un "manipulateur de résultat" le soin de... traiter les résultats obtenus

    Mais bon, on peut envisager (pour la simplicité de l'explication seulement) de s'en passer pour le gestionnaire d'utilisateurs...

    Enfin, j'aurais mon gestionnaire d'utilisateurs, qui fait appel au gestionnaire de connexion (et éventuellement aux systèmes de gestion et de traitement des requêtes) pour créer l'utilisateur courent.

    Sa seule responsabilité (c'est pour cela que, normalement, il faudrait recourir à un ensemble de classes pour gérer et traiter les requêtes au serveur) est... de s'assurer que l'utilisateur peut se connecter, et que le mot de passe introduit correspond à ce qui se trouve dans la base MySQL.

    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
    class UserManager
    {
            /* Comme tu travailles avec Qt, on n'autorise la création d'une 
             * instance que depuis la fenêtre principale...
             * Par facilité je choisi qu'elle s'appelle MyGUI (faudra adapter :D) 
             */
        friend class MyGUI;
        public:
            bool createUser(QString const & u, QString const & pass)
            {
                /* si un utilisateur est déjà connecté, on refuse d'en créer un autre
                 */
                if(user_!=NULL)
                    throw UserAllreadyCreated();
                /* à toi de créer la requête, de l'envoyer au serveur MySQL...
                 * et de la traiter... je considère que tu obtiens au final une
                 * structure donnant le nombre d'enregistrement trouvé,
                 * la somme SHA-1 du mot de passe et
                 * les droits accordés à l'utilisateur appelée result
                 */
               if(result.count==0)
                   throw UserDoesntExists();
               if( SHA_1(pass)!=result.pass)
                   throw BadLoginOrPassword();
               user_=new User(u, result.rights);
               return true;
            }
            /* on permet de détruire l'utilisateur en cours de fonctionnement
             * (généralement pour permettre à un autre de se connecter :D )
             */
            void disconnectUser()
            {
                delete user_;
                 user_ = NULL;
            }
            /* on peut récupérer une référence constante sur l'utilisateur */
            User const& user()const {return *user_;}
        private:
            UserManager(ConnectionManager * cm ):user_(NULL)
                                 connManager_(cm){}
            ~UserManager(){delete user_;}
            // copie et affectation interdite
            UserManager(UserManager const &);
            UserManager& operator = (UserManager const &);
            User * user_;
            ConnectionManager * connManager_;
    };
    NOTA: UserDoesntExists, UserDoesntExists et BadLoginOrPassword sont des classes d'exception qu'il t'appartient de créer, qui te permettront d'afficher un message adapté si l'utilisateur n'est pas créé

    Pour le reste, tout se fait au niveau de la fonction principale, mais, comme tu travailles avec Qt, je présumes (peut être à tord) que tu crées une interface graphique...

    Il y a, normalement, possibilité de récupérer l'instance de QApplication depuis n'importe où... C'est donc à ce niveau là que devront se trouver les instances de ConnectionManager et de UserManager.

    Je ne met que ce qui nous intéresse, mais elle ressemblera à quelque chose comme
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    MyGUI : public QMainWindow
    {
        public:
            MyGUI():connections_("http://127.0.0.1:port"), 
                 users_(&connManager_)
        {}
        UserManager const & users() const {return users_;}
        ConnectionManager const & connections() const{return connections_;}
        UserManager & users() {return users_;}
        ConnectionManager & connections() {return connections_;}
    }
    Comme tu n'aura qu'une instance de ton interface graphique, et qu'il n'y a, jamais qu'un gestionnaire de connexion et un gestionnaire d'utilisateur, avec, à chaque fois, une seule instance de connexion ou d'utilisateur, tu peux être sûr qu'il n'y aura... qu'un instance de connexion et une d'utilisateur (maximum) par application

    [EDIT]Est-il besoin de préciser que le code a été écrit à la volée, sans réflexion approfondie, et n'a absolument pas été testé
    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. [c#] Accesseurs sur tableaux d'une classe
    Par tribaleur dans le forum Windows Forms
    Réponses: 8
    Dernier message: 31/12/2009, 00h36
  2. Réponses: 5
    Dernier message: 07/02/2006, 14h05
  3. Outils pour creer les accesseurs et les mutateurs
    Par MarieMtl dans le forum MFC
    Réponses: 3
    Dernier message: 03/10/2005, 17h03
  4. [C#] [VS.NET] Peut on faire un accesseur sur objets?
    Par Designotik dans le forum Windows Forms
    Réponses: 3
    Dernier message: 06/01/2005, 21h56
  5. [Java 5] Réflexion sur les énumérations type-safe
    Par rozwel dans le forum Langage
    Réponses: 5
    Dernier message: 04/12/2004, 20h34

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