Problème avec le constructeur de copie

Fermé
razuki Messages postés 242 Date d'inscription lundi 17 décembre 2007 Statut Membre Dernière intervention 5 décembre 2012 - Modifié par razuki le 1/02/2011 à 17:31
Char Snipeur Messages postés 9696 Date d'inscription vendredi 23 avril 2004 Statut Contributeur Dernière intervention 3 octobre 2023 - 2 févr. 2011 à 12:57
Bonjour,

J'ai défini un classe Personnage. J'essaie de copier le Personnage goliath vers le Personnage david comme suit :

int main() 
{ 
 Personnage goliath("Epée aiguisée", 20); 
 Personnage david = goliath; 
... 
}


Voici les constructeurs que j'ai crée dans la classe Personnage :

Personnage::Personnage() : m_vie(100), m_mana(100) 
{ 
 m_arme = new Arme(); 
} 
Personnage::Personnage(string nomArme, int degatsArme) : m_vie(100), m_mana(100)
{
	m_arme = new Arme(nomArme, degatsArme);
}


Le compilateur me dit alors :

Undefined reference to 'Personnage::Personage(Personnage const&)


Ma question :
-- Le compilateur ne crée - t - il pas automatiquement le constructeur de copie ?
-- le problème serait - il ailleurs ?

Merci d'avance pour votre aide.
A voir également:

3 réponses

Char Snipeur Messages postés 9696 Date d'inscription vendredi 23 avril 2004 Statut Contributeur Dernière intervention 3 octobre 2023 1 297
1 févr. 2011 à 16:26
je sais pour le constructeur par défaut (sans argument) qu'il est fabriqué automatiquement sauf s'il y a un autre constructeur. Il en va peut être de même avec le constructeur par copie.
As tu déclarer le constructeur par copie ?
Met nous le .h de la class que nous puissions nous faire un avis.
0
razuki Messages postés 242 Date d'inscription lundi 17 décembre 2007 Statut Membre Dernière intervention 5 décembre 2012 1
1 févr. 2011 à 17:29
En fait je n'ai pas définit le constructeur de copie, je l'ai juste declaré ...
ce problème est résolu.
Un autre problème toujours lié au constructeur de copie :

-- j'ai deux Personnage david et goliath qui ont un pointeur arme pointant vers le meme objet arme (voir main ci-dessus).
-- j'ai détruit david ( d'abord son arme, puis lui meme ), puis j'ai détruit goliath et ceux en fin de main( )

goliath.~Personnage();
david.~Personnage();

Ma question :
est-ce normal que le compilateur ne rale pas, que le programme ne plante pas ... ?
En effet quand je détruit goliath l'arme disparait avec lui. Quand je tente de détruire david, le compilateur est censé cherche son arme ... NON ?

Merci d'avance pour votre aide.
0
Char Snipeur Messages postés 9696 Date d'inscription vendredi 23 avril 2004 Statut Contributeur Dernière intervention 3 octobre 2023 1 297
2 févr. 2011 à 08:13
encore une fois, difficile de dire, tu ne mets pas de code. Déjà pour dire il faudrait avoir le destructeur.
Ensuite, le destructeur s'appelle avec "delete" et non avec "~Personnage "
Pour finir il n'y a besoin d'appeler le destructeur qu'en cas d'objet alloué dynamiquement (de pointeur si tu préfères). Et là tu alloue deux objets normaux qui seront détruits automatiquement.

Dans la même veine, mais un peu différent, les membres dynamiques. La règle est simple : tout new correspond à un delete. Tes membres dynamiques ne sont détruit que si tu le fait explicitement dans le destructeur. C'est pour ça que pour répondre, nous avons besoin de morceau de codes.
0
razuki Messages postés 242 Date d'inscription lundi 17 décembre 2007 Statut Membre Dernière intervention 5 décembre 2012 1
2 févr. 2011 à 12:33
D'accord. Maintenant je cherche à provoquer un plantage. Arme est un pointeur dans Personnage. Le constructeur de copie que j'ai crée dans Personnage copie le pointeur et non pas l'objet pointé. david et goliath possède alors le meme objet arme. Et je me demande pourquoi ca ne plante pas.

Voici mon code :

Personnage.h
class Personnage
{
    public:
 
	Personnage();
	Personnage(std::string nomArme, int degatsArme);
	Personnage(const Personnage &personnageACopier);
    void recevoirDegats(int nbDegats);
    void attaquer(Personnage &cible);
    void boirePotionDeVie(int quantitePotion);
    void changerArme(std::string nomNouvelleArme, int degatsNouvelleArme);
    bool estVivant();
    void afficherEtat();
 
    ~Personnage();
 
 
    private:
 
    int m_vie;
    int m_mana;
	Arme* m_arme;
    //std::string m_nomArme; // Pas de using namespace std, donc il faut mettre std:: devant string.
    //int m_degatsArme;
 
 
};


Personnage.cpp
//Personnage::Personnage() : m_vie(100), m_mana(100), m_nomArme("Epée rouillée"), m_degatsArme(10) {}
Personnage::Personnage() : m_vie(100), m_mana(100)
{
	m_arme = new Arme();
}
//Personnage::Personnage(string nomArme, int degatsArme) : m_vie(100), m_mana(100), m_arme(nomArme, degatsArme) {}
Personnage::Personnage(string nomArme, int degatsArme) : m_vie(100), m_mana(100)
{
	m_arme = new Arme(nomArme, degatsArme);
}
 
Personnage::Personnage(const Personnage &personnageACopier)
{
    m_vie = personnageACopier.m_vie;
    m_mana = personnageACopier.m_mana;
    m_arme = personnageACopier.m_arme;
    //m_arme = new Arme(personnageACopier.m_arme);
 
}
 
Personnage::~Personnage()
{
	delete m_arme;
}
	void Personnage::recevoirDegats(int nbDegats)
	    {
		m_vie -= nbDegats;
		if (m_vie < 0)
			m_vie = 0;
	    }
		void Personnage::attaquer(Personnage &cible)
		{
			cible.recevoirDegats(m_arme->getDegats());
		}
 
	    void Personnage::boirePotionDeVie(int quantitePotion)
	    {
	    	m_vie += quantitePotion;
	    	if (m_vie > 100)
	    		m_vie = 100;
	    }
 
	    void Personnage::changerArme(std::string nomNouvelleArme, int degatsNouvelleArme)
	    {
	    	m_arme->changer(nomNouvelleArme, degatsNouvelleArme);
 
	    }
 
	    bool Personnage::estVivant()
	    {
	    	if (m_vie > 0)
	    		return true;
	    	else
				return false;
	    }
 
	    void Personnage::afficherEtat()
	    {
	        cout << "Vie : " << m_vie << endl;
	        cout << "Mana : " << m_mana << endl;
	        m_arme->afficher();
	    }


Voici mon main :

int main()
{
    // Création des personnages
    //Personnage david, goliath("Epée aiguisée", 20);
	Personnage goliath("Epée aiguisée", 20);
	Personnage david = goliath;
    // Au combat !
    goliath.attaquer(david);
    david.boirePotionDeVie(20);
    goliath.attaquer(david);
    david.attaquer(goliath);
    goliath.changerArme("Double hache tranchante vénéneuse de la mort", 40);
    goliath.attaquer(david);
 
    // Temps mort ! Voyons voir la vie de chacun...
    cout << "David" << endl;
    david.afficherEtat();
    cout << endl << "Goliath" << endl;
    goliath.afficherEtat();
    //goliath.~Personnage();
    //david.~Personnage();
 
    return 0;
}


Le resultat :
David
Vie : 40
Mana : 100
Arme : Double hache tranchante vénéneuse de la mort (Dégâts : 40)
 
Goliath
Vie : 80
Mana : 100
Arme : Double hache tranchante vénéneuse de la mort (Dégâts : 40)
0
Char Snipeur Messages postés 9696 Date d'inscription vendredi 23 avril 2004 Statut Contributeur Dernière intervention 3 octobre 2023 1 297
2 févr. 2011 à 12:57
bon, en effet, tu devrais avoir une erreur ou pas, je ne connais pas le comportement exact de "delete". J'ai trouvé ça qui donne un début de piste (cf. à partir du message de int21h) : https://openclassrooms.com/forum/sujet/c-new-delete-vs-mallocfree-68854
Il est possible que le delete vérifie ce qu'il a à détruite avant de le faire.
plusieurs tests possible, modifier le destructeur :
Personnage::~Personnage()
{
        cout<<"suppresion de l'arme stockée là : "<<(long)m_arme;
	delete m_arme;
}

modifier tes david et goliath par des pointeurs et utiliser directement le delete.
Bonne chance.
0