Bonjour à tous, j'essaie de faire le Javaquarium en C++ et je suis confronté à plusieurs erreur :
Je déclare la classe Aquarium dans Aquarium.h et la classe Poisson dans poisson.h. Un prototype de Poisson a un paramètre de type Aquarium, et du coup ça plante : identificateur 'Aquarium' (j'ai inclus Aquarium.h).
J'ai créé une méthode manger (type void et argument de type Aquarium) que j'utilise à plusieurs endroits et le compilo me dit qu'il est impossible de trouver la surcharge, qu'elle ne prend pas 1 argument et qu'elle n'a pas de pointeur this (alors qu'elle est dans une classe).
Le code :
Aquarium.h
#pragma once
#include <iostream>
#include <vector>
#include "Poissons.h"
using namespace std;
class Aquarium {
public:
Aquarium(int poissons = 0, int algues = 0);
int get_poissons() const;
int get_algues() const;
void ajouter_algue();
void enlever_algue();
void tour() const;
void enlever_poisson();
void ajouter_poisson(Poisson poisson);
vector<Poisson> get_liste_poissons() const;
private:
int _poissons; int _algues;
vector<Poisson> _liste_poissons;
};
Je déclare la classe Aquarium dans Aquarium.h et la classe Poisson dans poisson.h. Un prototype de Poisson a un paramètre de type Aquarium, et du coup ça plante : identificateur 'Aquarium' (j'ai inclus Aquarium.h).
Si tu lisais le message en entier, il ne dit pas que "identificateur Aquarium", mais aussi ce qu'il en pense. Par exemple que ce n'est pas le nom d'un type connu. Et aussi, dans quel fichier source, à quelle ligne.
C'est sans doute un problème d'ordre de déclarations. En C++ comme en C - et contrairement à Java -, on ne peut utiliser un nom de type que si il a été déclaré AVANT.
Dans a priori, il faudrait avoir une déclaration d'Aquarium avant la définition de Poisson. Mais la définition d'Aquarium nécessite aussi de savoir que Poisson est une classe.
Donc on est dans un problème de définition mutuelle, qui t'a certainement été expliqué quelque part.
Autre problème : dans tes appels de fonctions membres, tu passes les poissons et aquariums par COPIE.
Merci pour vos réponses, j'ai enlevé using et déclaré les classes dans les .h.
Maintenant, il me reste un problème : quand un poisson carnivore mange, le programme appelle la fonction mourir() pour le poisson visé .
void mourir() { delete this; }
Quand mourir() est appelé, j'ai une exception levée (violation d'accès en lecture, _Pnext a été 0xDDDDDDE1.) dans xmemory. J'ai vu plusieurs fois que la violation d'accès est due aux pointeurs. Je sais que this est un pointeur mais du coup comment supprimer le poisson et pas juste l'enlever de la liste de l'aquarium (c'est pas propre et ça utilise de la mémoire pour rien.) ?
Tu as un problème de conception, liés aux différences fondamentales entre langages.
En Java tu manipules des variables qui contiennent des références à des objets.
En C++, tes variables contiennent des objets. Et si tu fais a = b; a contient une COPIE de b. Alors qu'en Java, a désignera le MÊME OBJET que b.
Donc si tu veux qu'un objet représente un poisson, et qu'un poisson ne soit représenté que par un unique objet (ce qu'on appelle avoir une sémantique d'entité), il faut que ton programme manipule explicitement des références (au sens C++) et des pointeurs.
Ah, j'entends la sonnette, ce sont les petits camarades qui viennent prêcher pour les smart pointeurs qui sont venus délivrer le monde de l'enfer des pointeurs à poil inventés par Satan.
Salut ! Juste une petite remarque, la plupart du temps, en C++ on préfère utiliser des fonctionnalités de la bibliothèques standard (particulièrement celle de C++11 et des version ultérieures) que de devoir piocher dans les fonctionnalités du langage C. La paire rand()/srand() c'est du C, à la place on peut utiliser l'en-tête <random> qui fournit du stuff en rapport avec la génération de nombres pseudo-aléatoires et tout un tas de trucs dans l'esprit. Voici un lien de doc.
EDIT: C'est pas nous qui prêchons l'utilisation des pointeurs intelligents !! C'est RAII !
On ne touche pas à this, lui il aime pas qu'on l'emmerde, il est autonome et il n'a pas besoin d'aide.
D'accord donc pour chaque méthode de classe, je met des références aux paramètres. Et du coup, quand je remplacerai tous les paramètres par des références, delete this fonctionnera ou pas ?
Parce que j'ai suivi le cours sur C++ mais que j'ai pas trop compris l'utilité des pointeurs.
Et pour <random> j'ai déjà testé mais j'ai trouvé que la notation était un peu lourde pour le peu que je m'en servais. Quand j'aurai à faire de plus gros programmes avec plus d'aléatoires je m'en servirai.
Si tu n'as pas compris le fonctionnement des pointeurs, replonge toi dans ton cours et documente toi. Faire du C++ sans comprendre les pointeurs c'est faire du Java sans comprendre l'intérêt de l'encapsulation (comparaison stupide hein...). Tu trouves des tonnes d'explication sur les pointeurs, elles sont parfois bonnes, parfois mauvaises, moi j'ai bien compris l'intérêt du truc grâce à (en partie):
Pour rigoler, j'attend que la secte des Smart Pointers tente de fournir une explication accessible aux débutants :-) sans dire qu'un pointeur c'est une donnée qui contient l'adresse d'une (autre) donnée (*)
(*) ce qui est faux pour les pointeurs intelligents, puisqu'un shared pointer contient (dans les implémentations habituelles) l'adresse d'un "bloc de controle" avec compteur de références etc.
Tu veux dire quoi par le fait qu'un shared_ptr contienne l'adresse d'un bloc de contrôle ? Parce que dans la documentation il est cité qu'un shared_ptr contient un pointeur sur un objet et que la particularité de ce type de pointeur intelligent c'est que l'ownership peut être partagé (d'où le nom xD).
EDIT: Je viens de lire la doc de Microsoft, et en effet, ils parlent bien d'un bloc de contrôle. Ce qui parait logique quand on comprend le comportement d'un shared_ptr. Mais en plus de contenir l'adresse du bloc de contrôle, ils contiennent l'adresse de la ressource partagée.
Mais pourquoi ne pas utiliser un membre statique à la place d'un pointeur sur le bloc de contrôle ? Parce que c'est le bloc de contrôle qui gère la destruction de la ressource partagée ?
Une chose a faire avec ce type d'exercice, pour eviter les mauvaises surprises, et peut être comprendre pourquoi on a le droit de faire ceci, et pas le droit de faire cela, est de t'assurer que tes classes respectent la bonne sémantique.
En l'occurence, les aquariums, les poissons, les algue sont des entités, ce qui implique que les classes les représentant ne doivent être ni copiable, ni assignable.
PS: C'est d'ailleur la première question que tu doits te poser dès que tu décides de créer une classe: Quelle est sa sémantique ? Valeur ou Entité ?
Tu veux dire quoi par le fait qu'un shared_ptr contienne l'adresse d'un bloc de contrôle ? Parce que dans la documentation il est cité qu'un shared_ptr contient un pointeur sur un objet et que la particularité de ce type de pointeur intelligent c'est que l'ownership peut être partagé (d'où le nom xD).
EDIT: Je viens de lire la doc de Microsoft, et en effet, ils parlent bien d'un bloc de contrôle. Ce qui parait logique quand on comprend le comportement d'un shared_ptr. Mais en plus de contenir l'adresse du bloc de contrôle, ils contiennent l'adresse de la ressource partagée.
Mais pourquoi ne pas utiliser un membre statique à la place d'un pointeur sur le bloc de contrôle ? Parce que c'est le bloc de contrôle qui gère la destruction de la ressource partagée ?
- Edité par Daimyo_ il y a 36 minutes
Un membre statique ? Pour que tous les pointeurs intelligents désignent la même instance ????
Dans une implémentation typique, std::shared_ptr conserve deux pointeurs :
Un pointeur vers l'objet géré
Un pointeur vers le bloc de contrôle
Le bloc de contrôle est un objet alloué dynamiquement qui conserve :
soit un pointeur vers l'objet géré, soit l'objet géré lui-même
le destructeur (type-erased)
l'allocateur (type-erased)
le nombre de shared_ptrs qui possèdent l'objet géré
le nombre de weak_ptrs qui pointent sur l'objet géré
>>
---
Lorsqu'on détruit un shared_pointer, son destructeur met à jour le compteur de références dans le bloc de contrôle, et décide de libérer la ressource si il n'y a plus de "co-propriétaires" de l'objet.
D'accord c'est plus clair comme ça ! Merci. J'avais pensé à un membre statique qui ferait office de compteur pour les instances pointant sur la ressource partagée mais vu le traitement à faire pour que tout soit géré correctement ça serait minimaliste. Je ne pensais pas que le bloc de contrôle aurait autant de CoNtRoLe (ça arrive d'être stupide...) sur tout ce qui se trouve autour des shared_ptr.
La (mauvaise) idée d'utiliser un compteur statique vous a été AIMABLEMENT suggérée par le (très mauvais) exemple qui sert souvent d'introduction à la notion de membre statique, à savoir
"on veut créer des Machins, en leur attribuant automatiquement un numéro de série, qui s'incrémente à chaque fois"
La "solution" habituelle : ah ben y a qu'à mettre un compteur dans la classe.
Critique : Le compteur unique pour tout le monde répand une délicate odeur de Singleton.
Bon, on va dire que fabriquer des Machins et les estampiller, c'est le boulot d'un Fabricant de Machins. Y a qu'à en faire un objet. On en aura autant qu'on veut, c'est à eux qu'on s'adresse pour avoir un nouveau machin.
#include <iostream>
class Machin {
private:
int m_numero;
std::string m_nom;
public:
Machin(const std::string &nom, int numero)
: m_numero(numero)
, m_nom(nom)
{}
std::string to_string() const {
return m_nom + "#" + std::to_string(m_numero);
}
};
class Fabricant {
private:
int m_num = 1;
public:
Fabricant(int n = 0)
: m_num {n}
{}
Machin fabrique(const std::string & nom) {
return {nom, m_num++}; // le voila, ton machin.
}
};
int main() {
Fabricant f(1000);
Machin m1 = f.fabrique("toto"),
m2 = f.fabrique("titi");
std::cout << m1.to_string() << std::endl
<< m2.to_string() << std::endl;
return 0;
}
× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
× Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
Liens utiles pour le C++
Liens utiles pour le C++
https://zestedesavoir.com/tutoriels/822/la-programmation-en-c-moderne/
Liens utiles pour le C++
https://zestedesavoir.com/tutoriels/822/la-programmation-en-c-moderne/
https://zestedesavoir.com/tutoriels/822/la-programmation-en-c-moderne/
https://zestedesavoir.com/tutoriels/822/la-programmation-en-c-moderne/
Liens utiles pour le C++