Partage
  • Partager sur Facebook
  • Partager sur Twitter

question sur les objets

tutoriel c++

Sujet résolu
22 février 2020 à 14:36:45

Bonjour voila, alors j'ai fait un peu de java, je connais un peu la poo, et c'est vrai qu'avec java, on ne s'embête jamais avec des pointeurs.

Je suis en train de suivre le tutoriel sur le c++, je viens d'arriver à la partie poo, et je viens d'observer un phénomène que je ne comprends pas.

//main.cpp
#include <iostream>
#include <string>
#include <ctime>
#include "Personnage.h"
#include "Weapon.h"

using namespace std;

int main()
{
    Personnage david, goliath;
    //Création de 2 objets de type Personnage : david et goliath
 
    goliath.attack(david);    //goliath attaque david
    david.drinkHealthPotion(20); //david récupère 20 de vie en buvant une potion
    goliath.attack(david);    //goliath réattaque david
    david.attack(goliath);    //david contre-attaque... c'est assez clair non ?
    
    goliath.getWeapon().change("Double hache tranchante veneneuse de la mort", 40);
    goliath.attack(david);
 
    cout << "David" << endl;
    david.print();
    cout << endl << "Goliath" << endl;
    goliath.print();
 
    return 0;
}
//Personnage.cpp
#include <iostream>
#include <string>
#include "Personnage.h"
#include "Weapon.h"

using namespace std;

Personnage::Personnage() : b_health(100), b_mana(100) {}

Personnage::Personnage(string name, int damage) : b_health(100), b_mana(100), b_weapon(name, damage) {}

Personnage::Personnage(Weapon weapon) : b_health(100), b_mana(100), b_weapon(weapon) {}

Personnage::~Personnage()
{

}

void Personnage::getDamaged(int damage)
{
    b_health -= damage;
    if (b_health < 0)
        b_health = 0;
}
void Personnage::attack(Personnage &target)
{
    target.getDamaged(getWeapon().getDamage());
}

void Personnage::drinkHealthPotion(int quantityPotion)
{
    b_health += quantityPotion;
    if (b_health > 100)
        b_health = 100;
}

void Personnage::changeWeapon(Weapon newWeapon)
{
    b_weapon = newWeapon;
}
void Personnage::changeWeapon(string name, int damage)
{
    b_weapon.change(name, damage);
}

bool Personnage::isAlive() const
{
    return b_health > 0;
}

Weapon Personnage::getWeapon() const
{
    return b_weapon;
}
void Personnage::print() const
{
    cout << "sante " << b_health << "  |  mana " << b_mana;
    getWeapon().print();
}
#include <iostream>
#include <string>
#include "Weapon.h"

using namespace std;

Weapon::Weapon() : b_name("Epee rouillee"), b_damage(10) {}

Weapon::Weapon(string name, int damage) : b_name(name), b_damage(damage) {}

Weapon::~Weapon()
{
    
}

//Weapon.cpp
void Weapon::change(string name, int damage)
{
    b_name = name;
    b_damage = damage;
}

void Weapon::print() const
{
    cout << "  |  arme " << b_name << " | degats  " << b_damage << endl;
}
int Weapon::getDamage() const
{
    return b_damage;
}      

Si vous voulez que je vous mette les .h hésitez pas à demander.

Ma question c'est que lorsque j'écris goliath.getWeapon().change("Double hache tranchante veneneuse de la mort", 40); dans le main, et ben ça ne fait rien. Le cout juste après affiche toujours epee rouillee.

Mais si je remplace par goliath.changeWeapon("Double hache tranchante veneneuse de la mort", 40); , alors là miracle ça fonctionne. Le cout affiche bien le texte attendu. Pourtant, techniquement, ces deux fonctions font exactement la même chose. Alors je trouve ça incompréhensible.

Si quelqu'un peut m'expliquer les subtilités du c++ à cet égard... Ce serait très apprécié.

Je vous remercie d'avoir prit le temps de me lire. 

  • Partager sur Facebook
  • Partager sur Twitter
22 février 2020 à 15:18:16

Salut

goliath.getWeapon() renvoie juste une copie de ta variable membre b_weapon.

  • Partager sur Facebook
  • Partager sur Twitter
22 février 2020 à 16:50:45

Ces chapitres commettent une erreur de conception: une entité, cela ne doit pas se copier -- il faut `= delete`r  constructeur de copie et d'affectation, et non définir des choses qui ne riment à rien. Cf fAQ pour trouver une première définition d'"entité".

Une fois ce problème réglé, il te restera à bien gérer les durées de vie en manipulant des `unique_ptr<>` pour les nouvelles entités en sorties de factories et celles stockées dans des attributs, directement ou indirectement (std::vector<std::unique_ptr<Arme>>). Et pour les signatures des autres fonctions, utiliser des références.

Je n'ai pas trop le temps de faire un cours complet là. Je laisse à d'autre le soin de renvoyer vers des références plus complètes.

  • Partager sur Facebook
  • Partager sur Twitter
C++: Blog|FAQ C++ dvpz|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS| Bons livres sur le C++| PS: Je ne réponds pas aux questions techniques par MP.
23 février 2020 à 1:01:25

XxAnoth-ChaxX a écrit:

Salut

goliath.getWeapon() renvoie juste une copie de ta variable membre b_weapon.


Merci, du coup j'ai changé mes méthodes : 

//Personnage.cpp

Weapon* Personnage::getWeapon()
{
    Weapon* refWeapon(&b_weapon);
    return refWeapon;
}
void Personnage::print()
{
    cout << "sante " << b_health << "  |  mana " << b_mana;
    (*getWeapon()).print();
}
//Main.cpp
(*goliath.getWeapon()).change("Double hache tranchante veneneuse de la mort", 40);

Ca fonctionne mais je trouve ces notations.. un peu lourdes. Il y a t-il un autre moyen de l'écrire ? Ou de procéder ?  

De plus comme getWeapon() renvoie un pointeur désormais, je ne peux plus mettre le "const", mon IDE râle : impossible d'utiliser une valeur de type "const Weapon *" pour initialiser une entité de type "Weapon *"

Je ne peux pas écrire une fonction getWeapon const qui me renvoie une référence sur l'attribut b_weapon de ma classe personnage ? 

//Personnage.h
#ifndef DEF_PERSONNAGE
#define DEF_PERSONNAGE

#include <string>
#include <iostream>
#include "Weapon.h"

class Personnage
{
    private :

    int b_health;
    int b_mana;
    Weapon b_weapon;

    public :

    Personnage();
    ~Personnage();
    Personnage(std::string name, int damage);
    Personnage(Weapon weapon);
    void getDamaged(int damage);
    void attack(Personnage &target);
    void drinkHealthPotion(int quantityPotion);
    void changeWeapon(Weapon newWeapon);
    void changeWeapon(std::string name, int damage);
    bool isAlive() const;
    Weapon* getWeapon() ;
    void print();
};

#endif

Merci encore de me lire et pour vos réponses si rapides !

-
Edité par Parandore 23 février 2020 à 15:06:24

  • Partager sur Facebook
  • Partager sur Twitter
23 février 2020 à 16:56:49

Pour renvoyer une référence en gardant ta fonction constante :

class MyClass
{
    public:
    MyClass(int nombre);
    
    int & getNombre() const;
    
    private:
    int m_nombre;
};

MyClass::MyClass(int nombre) :
    m_nombre {nombre}
{}

int & MyClass::getNombre() const
{
    return m_nombre;
}

Mais comme l'a dit lmghs, le cours que tu suis est obsolète.

Comme déjà le fait d'utiliser using namespace std.

On dit plutôt "fonction membre" et non "méthode" ainsi que "variable membre" et non "attribut".

Dans ton constructeur Personnage, passe ta chaine de caractère par référence constante.

Il y a plein d'autres choses, mais si tu veux un cours de C++ moderne, en voici un.

  • Partager sur Facebook
  • Partager sur Twitter
23 février 2020 à 17:32:06

Bonjour,

Il me semble qu'il y a une petite erreur ( d'inattention ? )ligne 16 dans ton exemple, XxAnothChaxX ;), tu as oublié le const pour la référence vers le integer m_nombre:

const int & MyClass::getNombre() const
{
    return m_nombre;
}

Normalement, le compilateur renvoie une erreur si une fonction membre const renvoie une référence vers une variable membre non-const.

  • Partager sur Facebook
  • Partager sur Twitter

Mon site web de jeux SDL2 entre autres : https://www.ant01.fr

25 février 2020 à 14:58:12

Une dernière chose, maintenant que j'ai fait comme marqué plus haut : 

const Weapon & Personnage::getWeapon() const
{
    return b_weapon;
}

dans le main à la ligne 

goliath.getWeapon().change("Double hache tranchante veneneuse de la mort", 40);

Mon ide indique une erreur sur l'objet goliath : l'objet a des qualificateurs de type incompatibles avec le membre fonction "Weapon::change" -- le type d'objet est : const Weapon

Ce "const" commence à me prendre la tète. Est-ce vraiment nécessaire de le mettre partout ? 
J'avais lu dans le tutoriel qu'il fallait mettre const tout ce qui pouvait l'être, mais je me pose la question : est-ce que ça vaut vraiment le coup ? 

  • Partager sur Facebook
  • Partager sur Twitter
25 février 2020 à 15:10:28

Ta ligne n'a pas de sens.

L'arme elle même change (Grande magie, un objet métamorphe!).

Il sera plus logique que Goliath change d'arme.

  • Partager sur Facebook
  • Partager sur Twitter
25 février 2020 à 15:26:39

> est-ce que ça vaut vraiment le coup ?

OUI !!!

Grâce à cela, un code qui n'est pas sensé modifier l'arme d'une personne n'a pas le droit de le faire.

Ce qui est bien le cas ici.

Le plus simple ici, c'est faire une méthode "setWeapon" dans la classe de "goliath" et qui prendra une Arme en paramètre.

Ainsi, vous devrez gérer tout ce qu'implique un changement d'arme sur le personnage (buff, débuff, modificateur de toucher, esquive, etc...)

Ainsi, grâce à votre conception soignée avec des "const", cela vous oblige à vous poser les bonnes questions et à faire des implémentations robustes.

OUI !!! "const" aurait dû être le modificateur par défaut est "nonst" (!const) un mot clé.

  • Partager sur Facebook
  • Partager sur Twitter
Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.