[C++]Classe

Oliver -  
mamiemando Messages postés 33778 Date d'inscription   Statut Modérateur Dernière intervention   -
Bonjour/bonsoir tt le monde!
Je dois faire un programme en C++ permettant de gérer les comptes usagers des ordinateurs en utilisant les arbres binaires. J'ai commencé par faire une classe Usager qui contient des infos suivants : ID de l'usager, nom de l'usager, mot de passe, nombre de connexion invalide (nombre de connexion doit être inférieur à 3) et profil (usager ou administrateur). J'aimerais savoir si je suis sur la bonne voie avant de continuer, car je pense avoir de la misère avec mon constructeur.
Voici ce que j'ai fait jusqu'à date :


#include <iostream>


// Constantes pour profil
const unsigned int erreur = 0;
const unsigned int usager = 1;
const unsigned int admin = 2;


class Usager {
public :
Usager(int, char *, char *, int, const unsigned int); // Constructeur
~Usager(); // Destructeur

void setId(int);
void setNom(char *) ;
void setPassword(char *);
void setConnexion(int);
void setProfil(int);


int getId();
char getNom();
char getPassword();
int getConnexion();
int getProfil();


private :
int id;
char nom[25];
char password[25];
int connexionInvalide;
int profil;
};


ostream& operator<<(ostream&, const Usager&);
void ajouterLogfile(ofstream&, const Usager&);


Usager::Usager(int identite, char *name, char *pass, int connInv, const unsigned int u_a) {
id = identite;
connInv = 0;
connexionInvalide = connInv;
profil = u_a;

int taille1 = strlen(name);
taille1 = (longueur1 < 25 ? taille1 : 24);
strncpy(nom, name, taille1);
nom[taille1] = ‘\0’;

int taille2 = strlen(pass);
strcpy(password, pass, taille2);
password[taille2] = ‘\0’;
}


Usager::~Usager() {
cout << "Destructeur de l’objet Usager : " << nom << endl;
}


void Usager::setId(int i) {
id = i ;
return true ;
}


void Usager::setNom(char *n) {
int longueur1 = strlen(n);
longueur1 = (longueur1 < 25 ? longueur1 : 24);
strncpy(nom, n, longueur1);
nom[longueur1] = ‘\0’;
return true;
}


void Usager::setPassword(char *p) {
int longueur2 = strlen(p);
longueur2 = (longueur2 < 25 ? longueur2 : 24);
strncpy(password, p, longueur2);
password[longueur2] = ‘\0’;
return true;

}


void Usager::setConnexion(int nombre) {
if(nombre < 3)
{
connexionInvalide = nombre;
return true;
}

else
return false;
}


void Usager::setProfil(int pro) {
if (pro == 1 || pro == 2)
{
profil = pro;
return profil;
}

else
return false;
}


int Usager::getId() {
return id;
}


char Usager::getNom() {
return nom;
}


char Usager::getPassword() {
return password;
}


int Usager::getConnexion() {
return connexionInvalide;
}


int Usager::getProfil() {
return profil ;
}


ostream& operator<<(ostream &out, const Usager &user) {
out << user.id << ' '
<< user.nom << ' '
<< user.password << ' '
<< user.connexionInvalide << ' '
<< user.profil << flush;
return out;
}


void ajouterLogfile(ofstream &out, const Usager &user) {
int numero = 0;
while (numero++)
{
out.write(reinterpret_cast<const char*>(&user.numero),sizeof(unsigned int)); //Pour ecrire les chiffre 1,2,3,… devant chaque ligne. Je ne suis pas certain de ma démarche...
out.write(reinterpret_cast<const char*>(&user),sizeof(user));
}
}


Pourriez-vous me corriger ou commenter mon début de code s'il n'est pas correct? J'aimerais vraiment savoir si je pourrais continuer ainsi ou non. De plus, vu que j'ai très peu de connaissance sur les arbres binaires, est-ce qu'il faut que je fasse une autre classe (i.e. une classe dérivée de la classe Usager) ou que je peux mettre tout ça dans la même classe Usager (pour les arbres binaires).
Ce serait vraiment gentil les amis! MERCI BEAUCOUP!

2 réponses

mamiemando Messages postés 33778 Date d'inscription   Statut Modérateur Dernière intervention   7 884
 
En fait je n'ai pas compris pourquoi tu voulais faires arbres bianires. Car si l'idée c'est d'accéder rapidement aux informations d'une personne en connaissant son identifiant (nom de famille par exemple) c'est beaucoup plus simple de faire un std::map.

Accessoirement c'est dommage d'utiliser des char[25], qui limitent la taille de tes informations à 25 caractères, alors que tu pourrais directement utiliser des std::string. Du coup tu n'aurais même plus besoin de faire des strncpy, tu peux directement utilisre l'opérateur =. Bref c'est un peu comme si tu programmais en C++ mais en te restreignant aux fonctions du C ! C'est une peu dommage, non ?

Quelques petits remarques :

1- pour tes profils, en fait tu as un outil qui fait la même chose qui s'appelle enum

2- pour tes methodes get... comme celles-ci ne modifient pas le contenu de this, elles devraient en toute rigueur mentionner que this reste constant par cette méthode (en rajoutant const à la fin du prototype)

3- les attributs privés devraient être protected, en parituclier si tu es amené à faire un héitage public sur ta classe.

4- tu retournes des char pour getPassword (etc..) alors que ça devrait être des char * (et même plutôt des const char *). En l'occurence on va retourner des chaines, et pour éviter les pointeurs on va retourner une référence (tout se passe comme si on retournait un pointeur, donc on ne recopie pas la chaine, mais tout se passe comme si dans le code on manipulait directement la chaîne).

5- Afin de compresser le code j'ai mis directement le code des méthodes dans la classe, surtout que tu as mis tout dans le même fichier. Ta méthode de découpage est valable si tu as des méthodes avec un corps de fonction long à compiler, et que ce code est mis dans un .cpp séparé. En l'occurence les méthodes sont très courtes donc on peut les mettre directement en inline dans le .hpp

6- Attention à bien écrire std::cout (et non cout), où à mettre un using namespace std en début de fichier pour que ça compile partout. Un using namespace ne devrait jamais figurer dans un header (car tout fichier qui l'inclut serait touché). Moi je te conseille de ne jamais utiliser les "using namespace" et d'écrire explicitement les std::

7- Les fonctions qui retournent un booleen ne devrait pas retourner un type void mais un type bool.

8- Pour le profil, les connexions etc, passe par les enum

En somme voici ce que je te propose
#include <iostream>
#include <string>


enum profil_enum_t{erreur,usager,admin};
typedef enum profil_enum_t profil_t;

class Usager {
        protected:
                unsigned int id;
                std::string nom;
                std::string password;
                int connexionInvalide;
                profil_t profil;

        public :
                Usager(
                        unsigned id0,
                        const std::string & nom0,
                        const std::string & password0,
                        int connexionInvalide0,
                        const profil_t & profil0
                ):
                        id(id0),nom(nom0),password(password0),
                        connexionInvalide(connexionInvalide0),profil(profil0)
                {}

                ~Usager(){
                        std::cout << "Destructeur de l?objet Usager : " << nom << std::endl;
                }

                inline void setId(unsigned int id0){
                        id = id0;
                }

                inline void setNom(const std::string & nom0){
                        nom = nom0;
                }

                inline void setPassword(const std::string & password0){
                        password = password0;
                }

                inline void setConnexion(int c){
                        connexionInvalide = c;
                }

                inline void setProfil(const profil_t & profil0){
                        profil = profil0;
                }


                inline unsigned int getId() const{
                        return id;
                }

                inline const std::string & getNom() const{
                        return nom;
                }

                inline const std::string & getPassword() const{
                        return password;
                }

                inline int getConnexion() const{
                        return connexionInvalide;
                }

                int getProfil() const{
                        return profil;
                }
};

std::ostream & operator<<(std::ostream &out, const Usager &user) {
        // Comme les champs de user ne sont pas public
        // (protected ou private) il faut passer par les accesseurs
        out << user.getId() << ' '
                << user.getNom() << ' '
                << user.getPassword() << ' '
                << user.getConnexion() << ' '
                << user.getProfil() << std::flush;
        return out;
}


void ajouterLogfile(std::ostream &out, const Usager &user) {
//      int numero = 0;
//      while (numero++){
//              out.write(reinterpret_cast<const char*>(&user.numero),sizeof(unsigned int));
//              //Pour ecrire les chiffre 1,2,3,? devant chaque ligne. Je ne suis pas certain de ma démarche...
//              out.write(reinterpret_cast<const char*>(&user),sizeof(user));
//      }
//-----------------------------------
// Je ne suis pas sure d'avoir compris ce que tu voulais faire. Là je t'ai fait un
// compteur qui garde sa valeur d'un appel sur l'autre (static) et qui écrit le nom de l'utilisateur
// ajouté dans ce fichier....
        static unsigned int i = 1;
        out << i << '\t' << user.getNom() << std::endl;
}

int main(){
        // ...
        return 0;
}

Bonne chance
0
Oliver
 
Salut mamiemando!
En fait, ce que je voulais faire pour ma fonction void ajouterLogfile(std::ostream &out, const Usager &user) est d'énumérer (en commençant par 1) chaque ligne qui contiendra le id, nom, mot de passe, nombre de connexions invalides et profil. Par exemple :
1 5345 Oliver abc123 0 admin
2 9678 Sylvie def456 2 usager
etc...

Et aussi, pour les inline, comme je vais tout mettre ça dans un fichier .cpp, je peux enlever les inline sans problème n'est-ce pas?

Merci de m'avoir aidé!
0
mamiemando Messages postés 33778 Date d'inscription   Statut Modérateur Dernière intervention   7 884
 
void ajouterLogfile(std::ostream &out, const Usager &user) {
        static unsigned int i = 1;
        out << i << '\t' << user.getNom() << '\t' << user.getPassword() << '\t' << user.getConnexion() << '\t' << user.getProfil() << std::endl;
        ++i; // <-- oubli de ma part :p
}

Ceci dit c'est un bizarre de mettre un mot de passe en clair dans un fichier de log (si tu n'es plus en phase de debug). Personnellement ça me chagrine pas mal...

Et aussi, pour les inline, comme je vais tout mettre ça dans un fichier .cpp, je peux enlever les inline sans problème n'est-ce pas?

Oui. En fait le inline est utile :
- si la fonction est implémentée dans le hpp (pour éviter les multidéfinitions si le hpp est inclu par plusieurs fichiers)
- et si la fonction est très courte (concètement le compilateur remplace l'appel de la fonction par son code source).

Bonne chance
0