Exercice sur Pointeurs, classes, héritage...

Signaler
Messages postés
12
Date d'inscription
jeudi 22 décembre 2011
Statut
Membre
Dernière intervention
12 novembre 2010
-
Messages postés
12
Date d'inscription
jeudi 22 décembre 2011
Statut
Membre
Dernière intervention
12 novembre 2010
-
Bonjour à tous,

étant en train d'étudier le C++, j'ai quelques soucis avec un exercice.
C'est un classique dont je vous donne l'énoncé :
[b]1. Définissez la classe Animal qui sera muni des champs age, sexe et nom.
2. Définissez les classe Chien, Chat et Lapin qui héritent de Animal ainsi
que des constructeurs pour chacune de ces classes.
3. On consid`ere un tableaux de cinq pointeurs sur la classe Animal. Faites les modifications n ́ecessaires pour proposer une fonction remplissant ce tableau `a l’aide d’informations entrées au clavier, sachant que l’utilisateur précisera si l’animal considéré est un chien, un chat ou un lapin.
4. Faites les modifications nécessaires pour proposer une fonction qui retourne l’age moyen des animaux du tableau.
5. Faites les modifications nécessaires pour proposer une fonction qui indique le nombre de chiens, de chats et de lapins présents dans le tableau.
6. Faites les modifications n ́ecessaires pour proposer une fonction qui affiche à l'écran toutes les caractéristiques des animaux contenus dans le tableau.
7. Faites les modifications nécessaires pour proposer une fonction qui supprime du tableau tous les chats et chiens mâles.
Lorsque l’utilisateur lance le programme, il doit se trouver face au menu suivant :
• pour remplir le tableau d’animaux, tapez 1.
• pour afficher à l'écran toutes les caract ́eristiques des animaux contenus
dans le tableau, tapez 2.
• pour connaitre l’age moyen des animaux du tableau, tapez 3.
• pour connaitre le nombre de chiens, de chats et de lapins pr ́esents dans le
tableau, tapez 4.
• Pour supprimer du tableau tous les chats et chiens mâles, tapez 5.
Si l’utilisateur tape 0, il sort du programme, sinon l’utilisateur teste la fonction de la question correspondant au numéro inscrit après tapez et on retourne au menu principal./b

Jusqu'ici, je n'ai jamais eu de problème avec les exercices simples sur les pointeurs ou les classes. Mais là, tout se mélange et je m'y perds quelque peu...

Je vous mets le début de code que j'ai fait. Ca compile mais ça plante lamentablement lorsque après la saisie d'un 2eme animal.

[b]#include
#include <string>
#include <stdlib.h>

using namespace std;

class Animal{
protected:
int age;
char sexe;
string nom;
public:
Animal(int a=0, char s=NULL, string n=""){
age=a;
sexe=s;
nom=n;
}
void affiche(){
cout << age << " " << sexe << " " << nom << " ";
}
~Animal(){}
};

class Chien : public Animal {
private:
string race;
public:
Chien(int a=0, char s=NULL, string n="", string r="Chien"){
age=a;
sexe=s;
nom=n;
race=r;
}
void affiche(){
affiche();
cout << race << endl;
}
//~Chien(){}
};

class Lapin : public Animal {
private:
string race;
public:
Lapin(int a=0, char s=NULL, string n="", string r="Lapin"){
age=a;
sexe=s;
nom=n;
race=r;
}
void affiche(){
affiche();
cout << race << endl;
}

};

class Chat: public Animal {
private:
string race;
public:
Chat(int a=0, char s=NULL, string n="", string r="Chat"){
age=a;
sexe=s;
nom=n;
race=r;
}
void affiche(){
affiche();
cout << race << endl;
}
};

int menu () {
int choix;
cout << " 1 - Pour saisir un chat" <<endl;
cout << " 2 - Pour saisir un chien" <<endl;
cout << " 3 - Pour saisir un lapin" <<endl;
cout << endl << "Choix : ";
cin >> choix;
return choix;

}



void remplissage_tab(Animal *tab, int i){
int choix;
string n;
char s;
int a;
choix=menu();
cout << "Saisissez son nom : ";
cin >> n;
cout << "Saisissez son age : ";
cin >> a;
cout << "Saisissez son sexe M ou F : ";
cin >> s;
switch(choix){ case 1 : tab[i] = Chat(a,s,n);
break;
case 2 : tab[i] = Chien(a,s,n);
break;
case 3 : tab[i] = Lapin(a,s,n);
break;
}
}

void affichage_tab(Animal *tab, int i){
tab[i].affiche();
}


main(){
Animal * tab = new Animal[5];
int i;
for (i=0; i<5; i++) {
remplissage_tab(&tab[i],i);
}
for (i=0; i<5; i++) {
affichage_tab(&tab[i],i);
}
}
/b
A voir également:

14 réponses

Messages postés
12
Date d'inscription
jeudi 22 décembre 2011
Statut
Membre
Dernière intervention
12 novembre 2010
1
Encore moi ! Voilà donc ce que donne mon code pour le moment.
#include 

#define SIZE 2
using namespace std;

class Animal{
protected:
int age;
char sexe;
string nom;
public:	
Animal(int a=0, char s='F', string n=""){
age=a;
sexe=s;
nom=n;
}
void affiche(){
cout << age << " " << sexe << " " << nom;
}
virtual string type(){
return "Animal";
}
~Animal(){}
};

class Chien : public Animal {
private:
string race;
public:
Chien(int a=0, char s='F', string n="", string r="Chien"){
age=a;
sexe=s;
nom=n;
race=r;
}
void affiche(){
affiche();
cout << race << endl;
}
virtual string type(){
return race;
}
~Chien(){}
};

class Lapin : public Animal {
private:
string race;
public:
Lapin(int a=0, char s='F', string n="", string r="Lapin"){
age=a;
sexe=s;
nom=n;
race=r;
}
void affiche(){
affiche();
cout << race << endl;
}
virtual string type(){
return race;
}

};

class Chat: public Animal {
private:
string race;
public:
Chat(int a=0, char s='F', string n="", string r="Chat"){
age=a;
sexe=s;
nom=n;
race=r;
}
void affiche(){
affiche();
cout << race << endl;
}
virtual string type(){
return race;
}
};

int menu_animal () {
int choix;      
cout << "   1 - Pour saisir un chat" <<endl;
cout << "   2 - Pour saisir un chien" <<endl;
cout << "   3 - Pour saisir un lapin" <<endl; 
cout << endl << "Choix : ";     
cin >> choix;
return choix;   

}



void remplissage_tab(Animal **tab){
int i,a,choix;
string n;
char s;
for (i=0; i<SIZE; i++) {
cout << "Saisie de l'animal num " << i+1 << endl;
choix=menu_animal();
cout << "Saisissez son nom : ";
cin >> n;
cout << "Saisissez son age : ";
cin >> a;
cout << "Saisissez son sexe M ou F : ";
cin >> s;
switch(choix){                        		
case 1 : tab[i] = new Chat(a,s,n);
break; 
case 2 : tab[i] = new Chien(a,s,n); 
break;
case 3 : tab[i] = new Lapin(a,s,n); 
break;
}
}
}

void affichage_tab(Animal **tab){
int i;
cout << "Age " << "Sexe " << "Nom" << " Type" << endl;
for (i=0; i<SIZE; i++) {
tab[i]->affiche(); 
cout << " " <<tab[i]->type() << endl;
}
}

float age_moy(Animal **tab){
int i;
float som;
som=0;
for (i=0; i<SIZE; i++) {
som=som + tab[i]->age; 
}
return som;
}



main(){
Animal * tab[SIZE];
remplissage_tab(tab);
affichage_tab(tab);
system("pause");
}


Mon souci est dans la fonction age_moy
j'ai besoin d'accéder à l'attribut age qui est, à l'heure actuelle, en protected.
Quel est le meilleur moyen pour pouvoir y accéder ?
Je ne dois pas pouvoir tout passer en public j'imagine.
Créer une méthode virtuelle qui me retourne l'age de l'animal ?
Messages postés
3832
Date d'inscription
dimanche 12 décembre 2004
Statut
Modérateur
Dernière intervention
10 février 2021
118
Plusieurs erreurs:
- Remplissage_tab(&tab[i],i); Non. remplissage_tab(tab, i); Pas besoin de re-re-décaler l'indice. i s'en charge déjà.
- char s=NULL, bizarre char n'est pas un pointeur. Devrait être initialisé à 'f' ou 'h'. En soit ce n'est pas faux, ça équivaut à s = 0 ou s = '\0'.
- Vire #include <stdlib.h> c'est du C, pas du C++. En C++ on utilise 0 plutôt que NULL (NULL vaut toujours 0). Si tu as besoin de stdlib, alors écrit #include <cstdlib>
- Jamais de using namespace std; voir: http://0217021.free.fr/portfolio/axel.berardino/articles/bon-usage-using-namespace
Messages postés
12
Date d'inscription
jeudi 22 décembre 2011
Statut
Membre
Dernière intervention
12 novembre 2010
1
Merci beaucoup !
Ca ne plante plus, je me penche sur la suite maintenant.
Messages postés
1
Date d'inscription
mardi 5 janvier 2010
Statut
Membre
Dernière intervention
5 janvier 2010

merci mon ami et suivi et je voudrais m'explique comment en fonctionne la fonction gotoxy en langage dev c++
Messages postés
12
Date d'inscription
jeudi 22 décembre 2011
Statut
Membre
Dernière intervention
12 novembre 2010
1
Dans l'exercice il est demandé de ne munir la Animal que des champs âge, sexe et nom.
J'ai un tableau de pointeurs sur la classe Animal (comme demandé).
J'instancie les éléments du tableau à l'aide des classes filles Chien, Chat et Lapin en fonction de ce que l'utilisateur souhaite saisir comme animal.
Comment puis-je retrouver à quel type d'animal correspond un élément du tableau sachant qu'il n'y a que âge, sexe et nom qui apparaissent.
Y a-t-il un moyen de retrouver à partir de quelle classe un élément a été instancié ?

J'espère être clair dans ma demande.

Et si quelqu'un peut jeter un oeil à mes constructeurs et destructeurs car c'est encore assez flou pour moi...

Merci d'avance.
Messages postés
3832
Date d'inscription
dimanche 12 décembre 2004
Statut
Modérateur
Dernière intervention
10 février 2021
118
Il y a plusieurs solutions. Celle-ci n'est pas la meilleur, mais est simple à comprendre pour ton niveau actuel (pas de nouvelles notions nécessaires).

Met une méthode std::string type() dans chacune des classes, qui renvoit le vrai type de la classe.

Ex:
class A
{
public:
  virtual std::string type()
  {
    return "Je suis A";
  }
};
class B : public A
{
public:
  virtual std::string type()
  {
    return "Je suis B";
  }
};

A* a = new B;
a->type(); // Renverra Je suis B.


Virtual veut dire: La méthode a le droit d'être redéfinit dans la classe fille.
Messages postés
12
Date d'inscription
jeudi 22 décembre 2011
Statut
Membre
Dernière intervention
12 novembre 2010
1
Merci CptPingu, cela me sera sans doute utile mais dans cet exercice, je ne vois pas comment je pourrai interpréter le résultat. Par exemple pour compter le nombre de chats, de chiens... ou Supprimer les chats et les chiens mâles.
Dans mon code, j'ai commencé à mettre une donnée membre race (que je devrais renommer en type plutôt) dans chaque classe fille.
C'est sans doute comme ça que je pourrai plus facilement m'en sortir.
Mais il me vient alors un autre problème. Sachant que cette donnée n'apparaitra pas dans le tableau constitué d'éléments, y a-t-il un moyen de retrouver cette donnée membre ?
Messages postés
3832
Date d'inscription
dimanche 12 décembre 2004
Statut
Modérateur
Dernière intervention
10 février 2021
118
Oui, si des méthodes publiques utilisent la race en interne, ce n'est pas gênant.

Ex:
class A
{
public:
  virtual std::string type()
  {
    return "Je suis A";
  }
};
class B : public A
{
public:
  virtual std::string type()
  {
    // On considère que _race = "pouet";
    return "Je suis B et la race est : " + _race;
  }
private:
  std::string _race;
};

A* a = new A;
A* b = new B;

a->type(); // Affichera "Je suis A"
b->type(); // Affichera "Je suis B et la race est : pouet"
Messages postés
3832
Date d'inscription
dimanche 12 décembre 2004
Statut
Modérateur
Dernière intervention
10 février 2021
118
Version propre pour les questions 1, 2 et 3.

#include 

#define SIZE 5

class Animal
{
public:
  Animal(int age, char sexe, const std::string& nom);
  virtual ~Animal();
  virtual void affiche();
protected:
  int _age;
  char _sexe;
  std::string _nom;
};

Animal::Animal(int age, char sexe, const std::string& nom)
  : _age(age), _sexe(sexe), _nom(nom)
{
}

void Animal::affiche()
{
  std::cout << _age << " " << _sexe << " " << _nom;
}

Animal::~Animal()
{
}

class AnimalDeRace : public Animal
{
public:
  AnimalDeRace(int age, char sexe, const std::string& nom,
const std::string race);
  virtual void affiche();
  virtual ~AnimalDeRace();
protected:
  std::string _race;
};

AnimalDeRace::AnimalDeRace(int age, char sexe, const std::string& nom,
   const std::string race)
  : Animal(age, sexe, nom), _race(race)
{
}

void AnimalDeRace::affiche()
{
  Animal::affiche();
  std::cout << " " << _race;
}

AnimalDeRace::~AnimalDeRace()
{
}

class Chien : public AnimalDeRace
{
public:
  Chien(int age, char sexe, const std::string& nom,
const std::string race="Chien");
  virtual ~Chien();
};

Chien::Chien(int age, char sexe, const std::string& nom,
     const std::string race)
  : AnimalDeRace(age, sexe, nom, race)
{
}

Chien::~Chien()
{
}

class Chat : public AnimalDeRace
{
public:
  Chat(int age, char sexe, const std::string& nom,
const std::string race="Chat");
  virtual ~Chat();
};

Chat::Chat(int age, char sexe, const std::string& nom,
     const std::string race)
  : AnimalDeRace(age, sexe, nom, race)
{
}

Chat::~Chat()
{
}

class Lapin : public AnimalDeRace
{
public:
  Lapin(int age, char sexe, const std::string& nom,
const std::string race="Lapin");
  virtual ~Lapin();
};

Lapin::Lapin(int age, char sexe, const std::string& nom,
     const std::string race)
  : AnimalDeRace(age, sexe, nom, race)
{
}

Lapin::~Lapin()
{
}

int menu()
{
  int choix;
  std::cout << " 1 - Pour saisir un chat" << std::endl
    << " 2 - Pour saisir un chien" << std::endl
    << " 3 - Pour saisir un lapin" << std::endl
    << std::endl
    << "Choix : ";
  std::cin >> choix;

  return choix;
}

void remplissage_tab(Animal** tab, int i)
{
  std::string nom;
  char sexe;
  int age;
  int choix = menu();
  std::cout << "Saisissez son nom : ";
  std::cin >> nom;
  std::cout << "Saisissez son age : ";
  std::cin >> age;
  std::cout << "Saisissez son sexe M ou F : ";
  std::cin >> sexe;
  switch (choix)
  {
    case 1: tab[i] = new Chat(age, sexe, nom);
      break;
    case 2: tab[i] = new Chien(age, sexe, nom);
      break;
    case 3: tab[i] = new Lapin(age, sexe, nom);
      break;
  }
}

void affichage_tab(Animal** tab)
{
  for (int i = 0; i < SIZE; ++i)
  {
    tab[i]->affiche();
    std::cout << std::endl;
  }
}

int main()
{
  Animal* tab[SIZE] = {0};

  for (int i = 0; i < SIZE; ++i)
    remplissage_tab(tab, i);

  affichage_tab(tab);

  return 0;
}
Messages postés
12
Date d'inscription
jeudi 22 décembre 2011
Statut
Membre
Dernière intervention
12 novembre 2010
1
Bonjour,

peux-tu m'expliquer pourquoi tu créés une nouvelle classe AnimalDeRace ?

Comment tu fais pour intégrer ton code de cette façon avec l'indentation ? Quand je fais un copier/coller, j'ai tout aligné à gauche comme tu as pu le voir dans le premier post...

Merci
Messages postés
3832
Date d'inscription
dimanche 12 décembre 2004
Statut
Modérateur
Dernière intervention
10 février 2021
118
peux-tu m'expliquer pourquoi tu créés une nouvelle classe AnimalDeRace ?

Parce que Chat, Chien et Lapin ont les mêmes propriétés. Donc je les factorise dans une classe au dessus, afin de ne pas répéter les mêmes choses. Je met "_race" et "affiche" dans AnimalDeRace, et je dis juste à Lapin, Chat et Chien d'en hériter. Pas besoin de réécrire trois fois la méthode affiche, ni d'avoir à réécrire 3 fois l'attribut _race.

Comment tu fais pour intégrer ton code de cette façon avec l'indentation ? Quand je fais un copier/coller, j'ai tout aligné à gauche comme tu as pu le voir dans le premier post...

Tu as des boutons de présentations dans la boîte de dialogue. Sinon tu ajoute un [ code=cpp] // Ton code /code (sans l'espace avant code).
Messages postés
12
Date d'inscription
jeudi 22 décembre 2011
Statut
Membre
Dernière intervention
12 novembre 2010
1
Tu as des boutons de présentations dans la boîte de dialogue. Sinon tu ajoute un [ code=cpp] // Ton code /code (sans l'espace avant code).


Oups, j'avais pas vu ces boutons. J'en profite pour utiliser celui de citation :-)

Merci
Messages postés
3832
Date d'inscription
dimanche 12 décembre 2004
Statut
Modérateur
Dernière intervention
10 février 2021
118
(int a=0, char s='F', string n="")

On évite les champs par défaut. Le constructeur est là pour forcer l'initialisation de certains attributs. Tu annules une partie de son utilité en faisant cela.

using namespace std;

Encore une fois, jamais jamais de using namespace std; !
Lis ceci: Du bon usage du using namespace std

Les constructeurs doivent être virtuels.

Re-Regarde attentivement la version propre que je t'ai envoyé. Tu fais beaucoup d'erreur que je t'avais déjà corrigé.

j'ai besoin d'accéder à l'attribut age qui est, à l'heure actuelle, en protected.
Quel est le meilleur moyen pour pouvoir y accéder ?


Tu ajoutes une méthode int getAge() dans Animal.
int Animal::getAge()
{
  return _age;
}

Par héritage, tous le monde l'aura.
Messages postés
12
Date d'inscription
jeudi 22 décembre 2011
Statut
Membre
Dernière intervention
12 novembre 2010
1
Encore une fois, jamais jamais de using namespace std; !
Lis ceci: Du bon usage du using namespace std


J'ai bien vu ta remarque concernant le namespace std
Ce que je voulais te préciser c'est que mon prof l'utilise. Pas bien oui. J'ai donc laissé et adapté avec ce que tu m'avais donné.

Je vais aussi virer les valeurs par défaut des constructeurs.

Ok pour l'histoire de l'attribut. J'ai pigé le truc.

Merci