[C++]Quelques questions

alexandra -  
mamiemando Messages postés 33778 Date d'inscription   Statut Modérateur Dernière intervention   -
Hello,

Je suis débutante et aurai quelques questions à vous posez
j'ai 3 class Animal, Tigre, Test
Tigre hérite de Animal
class Test{
Animal [] tabAnimaux; //tableaux contenant les animaux
int taille; //taille du tableaux
int nbElements; //nombres de cases libres du tableaux

void augmenter_taille(int nb){
//?
}

Comment s'écrit la méthode augmenter_taille

int main(){
Animal [] animaux;
for(int i=0; i<50; i++)
animaux [i] = new Tigre();
}
}

Est-ce que cette écriture est possible :
animaux [i] = new Tigre(...);

Si ce n'est pas le cas, comment faire pour ajouter des Tigres dans le tableau ?

Merci

7 réponses

mamiemando Messages postés 33778 Date d'inscription   Statut Modérateur Dernière intervention   7 884
 
Allocation et classe Test

Bon alors attention car new crée une instance et retourne l'adresse de l'instance. De plus qui dit new dit delete. Donc le plus simple c'est d'appeler directement le constructeur, ce qui évite les soucis d'allocation.
Attention aussi, car tu veux affecter animaux[i] alors que le tableau n'est pas alloué.

En gros ça donne :
Animal [50] animaux;
for(int i=0; i<50; i++)
  animaux [i] = Tigre();
}

Si tu ne connais pas la taille a priori de ton tableau, le plus simple c'est d'utiliser la classe std::vector :
#include <vector>
#include <iostream>

int main(){
  unsigned int n=28;
  std::vector<Animal> animaux;
  for(unsigned int i=0;i<n;++i)  animaux.push_back(Tigre());
  std::cout << "Il y a " << animaux.size() << " animaux"  << std::endl;
  return 0;
}

L'avantage de la classe std::vector c'est qu'elle fait exactement ce que tu essayes de faire dans ta classe Test. Pour plus d'infos :
https://community.hpe.com/t5/custom/page/page-id/HPPSocialUserSignonPage?redirectreason=permissiondenied&referer=https%3A%2F%2Fcommunity.hpe.com%2Ft5%2FServers-Systems-The-Right%2FSGI-com-Tech-Archive-Resources-now-retired%2Fba-p%2F6992583

Les méthodes
#include <iostream>

class Plop{
  protected:
  int x;
  public:
  Plop(int x0=0):x(x0){}
  void f(){
    std::cout << x << std::endl;
  }
};

// Attention à bien faire un héritage public !!!
class Plop_fille : public Plop{
  //...
}

int main(){
  Plop p = Plop(4);
  p.f();
  Plop_fille p = Plop_fille(4);
  p.f();
  return 0;
}

Si tu as besoin de réimplémenter des méthodes dans la classe fille, utilise le mot clé virtual.

Bonne chance
0
alexandra
 
Merci de la réponse.

Dans le cas ou il y a héritage, par exemple une classe B hérite d'une classe A pour faire ceci :
A a = new B();

Il faut donc obligatoirement crée un destructeur pour pouvoir utiliser new, c'est ça ?

autre question :
Comment fait-on pour détruire un tableau a 2 dimensions en C++.
Par exemple pour détruire le tableau [10][30]
et pour la destruction d'un int, double etc ...
int valeur;

Merci
0
mamiemando Messages postés 33778 Date d'inscription   Statut Modérateur Dernière intervention   7 884
 
Non en fait tu as toujours un destructeur par defaut. Si tu implémentes un destructeur, il tu "delete" tous les objets que tu as alloué avec un "new" dans le constructeur. Personnellement je n'utilise jamais de new, et donc jamais de delete.

Exemple
class tapir{
 //...
};

class plop{
  protected:
  tapir *t;

  public:

  plop(unsigned int n=0){
    t = new tapir();
  }

  ~plop(){
    delete t;
  }
};

Attention à bien associer les news et les delete au même niveau car sinon c'est le meilleur moyen de faire des double free ou d'oublier de désallouer de la mémoire. En particulier si l'on considère cet exemple
class mamie{
  protected:
  void *adresse;
  public:
  mamie(void *a):adresse(a){}
};

l'objet pointé par adresse a été créé a l'extérieur de la classe mamie, et donc la classe mamie n'a pas à désallouer ce pointeur. Dans le cas de la classe tapir par contre, le constructeur a bien alloué le pointeur donc il est normal que le destructeur le libère. Mais comme je te l'ai dit tout à l'heure normalement tu peux presque tout le temps te passer des news.

Allocation statique et dynamique

Il faut bien voir qu'en C (ou C++) déclarer un int x[50], c'est comme si tu déclarais un int. Pas de malloc, pas de new, donc pas de free ou de delete, la variable est automatiquement détruite à la fin du "scope"
{// <--- début du scope de x
  int x[50];
   if(...){// <--- début du scope de y
      char y;
   }// <--- fin du scope de y
   for(...){// <--- début du scope de z
      long p;
   }// <--- fin du scope de z
} // <--- fin du scope de x

A chaque fois que tu atteins une fin de scope les variables locale crées dans ce scope sont désallouées (et éventuellement recrée si on est dans un boucle, comme par exemple pour z)

Bonne chance
0
alexandra
 
Tu dis que tu n'utilises jamais de new mais comment est-ce que tu fais lorsqu'il y a de l'héritage ?
Par exemple, admettons qu'on ait une liste d'Animaux :
vector<Animal*> listes;

Et qu'Animal est la classe mère de Tigre et Serpent.
Pour ajouter des Tigre ou Serpent à cette liste, il faut faire :
Animal* tigre = new Tigre();
listes.push_back(tigre);

pour ajouter un tigre ou
Animal* serpent = new Serpent();
listes.push_back(serpent);

pour ajouter un Serpent.

Si tu n'utilises pas de new, comment est-ce que tu ferais pour pouvoir utiliser cette liste ?
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
mamiemando Messages postés 33778 Date d'inscription   Statut Modérateur Dernière intervention   7 884
 
Bon déjà un vecteur ce n'est pas une liste parce que c'est adjacent en mémoire, donc c'est plus proche du tableau que de la liste.

Ensuite je n'utilise des pointeurs que quand c'est nécessaire (ie si l'objet a déjà été créé en mémoire, et auquel cas je récupère son adresse avec l'opérateur &). Sinon je stocke directement l'objet.

Exemple

#include <vector>
#include <iostream>

struct plop{
  double i[10000]; // un plop c'est gros :-)
  int x;

  plop(x0=0):x(x0){}
};

int main(){
  const unsigned int n = 69;
  // Je crée plein d'objets plop
  std::vector<plop> u(n);
  for(unsigned int i=0;i<n;++i) u[i] = plop(2*i + 3); // je stocke l'objet

  // Je veux réutiliser ces objets mais ils 
  // sont déjà crées donc je vais chopper 
  // leur adresse qui elle, est beaucoup 
  // plus petite (la taille  d'une adresse)
  std::vector<plop *> v(n); 
  for(unsigned int i=0;i<n;++i) v[i] = &u[i]; // je stocke l'adresse

  // Afficher les (u[i]).x et les (v[i])->x
  for(unsigned int i=0;i<n;++i){
    std::cout << i << '\t' << (u[i]).x << '\t' << (v[i])->x << std::endl;
  }
  return 0;
}
0
Char Snipeur Messages postés 9813 Date d'inscription   Statut Contributeur Dernière intervention   1 299
 
Salut.
Pour reprendre ton exemple :
Serpent serpent();
listes.push_back(&serpent);

l'intéret c'est que serpent reste un Serpent au sein du tableau "listes"
C'est à dire que normalement (si Mamiemando pouvait confirmé :) il est possible que ça ne soit valable que pour les membres virtual) si serpent est le premier membre de listes, en fesant listes[0]-> tu peux accéder au données propres à Serpent.
0
mamiemando Messages postés 33778 Date d'inscription   Statut Modérateur Dernière intervention   7 884
 
En fait c'est plutôt au niveau des dynamic_cast qu'il faut regarder, mais de manière générale, c'est mal de mélanger les torchons et les salades.

Moi je te conseille de mettre dans la mesure du possible dans un container uniquement des objets homogènes, ou de partir du principe que les objets stockés dans ce container sont du type passé en paramètre template du container.
0