J'ai tenté d'appliquer le pattern NVI.
Voici le code, bonne lecture! :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94 /****Character.h****/ #ifndef Character_H #define Character_H #include <ostream> #include <string> #include "Weapon.h" //#include "Inventory.h" class Character { public : Character() {} Character(std::string name, int life) : _name(name), _lifePoint(life) { _alive = true; std::cout << "Character -> \'" << _name << "\' created" << std::endl; } //Les wrapper publics permettant d'appeler //les fonctions virtuelles des classes filles void attack(Character* ennemy) {do_attack(ennemy);} void attacked(Character* attacker) {do_attacked(attacker);} Weapon* getWeapon() {return do_getWeapon();} void setWeapon(Weapon* weapon) {do_setWeapon(weapon);} //Comportement de base de la fonction defini par les deux //premieres lignes puis spécialisation appelé par do_dies() void dies() { std::cout << _name << " is dead" << std::endl; _alive = false; do_dies(); } //Les getter/setter std::string getName() {return _name;} int getLifePoint() {return _lifePoint;} void setLifePoint(int lifePoint) {_lifePoint = lifePoint;} bool getAlive() {return _alive;} void setAlive(bool alive) {_alive = alive;} virtual ~Character() { std::cout << "Character ->\'" << _name << "\' Destroyed" << std::endl;} private : //Les méthodes abstraites sont la partie customisable de l'interface virtual void do_attack(Character *ennemy) = 0; virtual void do_attacked(Character* attacker) = 0; virtual Weapon* do_getWeapon() = 0; virtual void do_setWeapon(Weapon* weapon) = 0; virtual void do_dies() = 0; //Noter que meme les attributs propre a Character sont private //Si j'ai bien compris, cela renforce l'encapsulation et empeche //la classe fille de redefinir des comportements faisant partie //de la partie constante de l'interface. std::string _name; int _lifePoint; bool _alive; }; class Warrior : public Character { public : Warrior(std::string name, int life) : Character(name, life) { _weapon = new Weapon(); std::cout << "Character created" << std::endl; } //Si je decommente delete _weapon, j'obtiens un segfault parce que //l'arme Flame thrower est défruite deux fois. //Je ne comprends pas pourquoi virtual ~Warrior() {/*delete _weapon;*/} private : virtual void do_attack(Character *ennemy); virtual void do_attacked(Character *attacker); //Et on retrouve ici la specialistion de do_dies virtual void do_dies() {_weapon->setUsable(false);} virtual Weapon* do_getWeapon() {return _weapon;} virtual void do_setWeapon(Weapon* weapon) {_weapon = weapon;} Weapon *_weapon; }; #endif
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31 /****Character.cpp****/ #include <ostream> #include "Character.h" using namespace std; void Warrior::do_attack(Character *ennemy) { if (_weapon->isUsable()) ennemy->attacked(this); else std::cout << getName() << " does not have a weapon" << endl; } void Warrior::do_attacked(Character *attacker) { int lifePoint = getLifePoint(); int damage = attacker->getWeapon()->getDamage(); switch(damage > lifePoint){ case true : damage = lifePoint; setLifePoint(0); dies(); break; case false : setLifePoint(lifePoint - damage); break; } cout << getName() << " lost " << damage << " life point" << endl; }
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 /****Weapon.h****/ #ifndef WEAPON_H #define WEAPON_H #include <iostream> #include <string> class Weapon { public : Weapon () : _usable(false) {} Weapon(std::string name, int damage) : _name(name), _damage(damage), _usable(true) { std::cout << "Weapon -> \'" << _name << "\' created" << std::endl;} ~Weapon(){ std::cout << "Weapon -> \'" << _name <<"\' Destroyed" << std::endl; } int getDamage() {return _damage;} bool isUsable () {return _usable;} void setUsable(bool usable) {_usable = usable;} private: std::string _name; int _damage; bool _usable; }; #endifMes principales questions sont intégrées en commentaires dans le code.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 /*Et un petit main pour tester*/ #include <ostream> #include "Character.h" #include "Weapon.h" //#include "Inventory.h" //#include "Item.h" using namespace std; int main() { cout << "\n\\=*=*=*=*=*=*=*=*=*Creation=*=*=*=*=*=*=*=*=*=/\n" << endl; Warrior a("Mike", 50); Warrior b("Gob", 20); Weapon sword("Sword", 25); Weapon flameThrower("Flame Thrower", 45); a.setWeapon(&sword); b.setWeapon(&flameThrower); cout << "\n\\=*=*=*=*=*=*=*=*=*Operation=*=*=*=*=*=*=*=*=*=/\n" << endl; a.attack(&b); cout << "\n\\=*=*=*=*=*=*=*=*Destructions=*=*=*=*=*=*=*=*=/\n" << endl; return 0; }
(principalement, le destructeur de Warrior me pose problème...)
Sinon, j'attends bien évidemment des critiques (constructives!) sur mon implémentation de ce pattern et sur mon code ne général.
Ce code n'est qu'un code d'exercice, il se veut donc volontairement simplifier.
Merci d'avance à tous ceux qui vont prendre de leur précieux temps pour lire mon code et rédiger une réponse me permettant, ultimement, d'améliorer mes connaissances du C++.
Partager