CPP04 1.0
読み取り中…
検索中…
一致する文字列を見つけられません
main.cpp
[詳解]
1/* ************************************************************************** */
2/* */
3/* ::: :::::::: */
4/* main.cpp :+: :+: :+: */
5/* +:+ +:+ +:+ */
6/* By: kamitsui <kamitsui@student.42tokyo.jp> +#+ +:+ +#+ */
7/* +#+#+#+#+#+ +#+ */
8/* Created: 2025/05/29 23:19:21 by kamitsui #+# #+# */
9/* Updated: 2025/06/06 12:27:51 by kamitsui ### ########.fr */
10/* */
11/* ************************************************************************** */
12
29#include "AMateria.hpp"
30#include "Character.hpp"
31#include "Cure.hpp"
33#include "ICharacter.hpp"
34#include "IMateriaSource.hpp"
35#include "Ice.hpp"
36#include "Logger.hpp"
37#include "MateriaSource.hpp"
38#include "ScopedPointer.hpp"
39#include <cstdlib> // For EXIT_FAILURE
40
41// Forward declarations for helper functions
42#ifdef DEBUG_MODE
43static int testBasicRaii(void);
44static int testCharacterInventoryLimits(DroppedMateriaManager *droppedManager);
45static int testMateriaSourceLimits();
46static void testCharacterDeepCopy(DroppedMateriaManager *droppedManager);
47static void testCharacterDeepCopyAssignment(DroppedMateriaManager *droppedManager);
48#endif
49
63int main() {
64 IMateriaSource *src = new MateriaSource();
65 src->learnMateria(new Ice());
66 src->learnMateria(new Cure());
67
68 ICharacter *me = new Character("me");
69
70 AMateria *tmp;
71 tmp = src->createMateria("ice");
72 me->equip(tmp);
73 tmp = src->createMateria("cure");
74 me->equip(tmp);
75
76 ICharacter *bob = new Character("bob");
77
78 me->use(0, *bob);
79 me->use(1, *bob);
80
81 delete bob;
82 delete me;
83 delete src;
84
85#ifdef DEBUG_MODE
86
87 // Create instance DroppedMateriaManager
88 // This is the specific substance of the "system for managing dropped Materia.
89 DroppedMateriaManager droppedManager;
90
91 std::cout << "\n--- More Tests ---" << std::endl;
92 testBasicRaii();
93 testCharacterInventoryLimits(&droppedManager);
94 testMateriaSourceLimits();
95 testCharacterDeepCopy(&droppedManager);
96 testCharacterDeepCopyAssignment(&droppedManager);
97
98 droppedManager.displayDroppedMaterias(); // display current Dropped Mateias.
99 // don't have to call delete ( Because the destructor automatically calls clearAll().)
100#endif // DEBUG_MODE
101
102 return 0;
103}
104
105// --- Helper Function Implementations ---
106
107#ifdef DEBUG_MODE
108static int testBasicRaii(void) {
109 LOG_INFO("--- Test Basic with ScopedPointer ---");
110
111 // ScopedPointer is placed on the stack and is automatically released when exiting scope.
115
116 try {
117 // Create Instance of IMateriaSource
118 src.reset(new MateriaSource()); // If new fails, throw bad_alloc
119
120 // Learn Materia : Materia *m->clone() and delete m are performed.
121 src->learnMateria(new Ice());
122 src->learnMateria(new Cure());
123
124 // I think better code support Owner Ship.
125 // It is desirable that the implementation of ‘new Icd()’ passed as an argument be owned by the caller.
126 // The code example is as follows.
127 // (however, this approach is not required for the assignment, so it will not be used).
128 // ******* example code ***********
129 // ScopedPointer<AMateria> ice_to_learn(new Ice()); // If new Ice() failed throw bad_alloc
130 // ScopedPointer<AMateria> cure_to_learn(new Cure()); // If new Cure() failed throw bad_alloc
131 // if (src.get()) {
132 // src->learnMateria(ice_to_learn.get()); // learnMateria does not take ownership
133 // src->learnMateria(cure_to_learn.get());
134 //}
135 // ******* code end ***********
136 // ice_to_learn and cure_to_learn are automatically released when exiting the scope.
137 // If learnMateria takes ownership (does not delete internally), it must be passed in release().
138 // current design: learnMateria clones, so passed materia is caller's responsibility.
139
140 // Create Instance ICharacter.(me's interface)
141 me.reset(new Character("me")); // If new Character() fails, throw bad_alloc.
142
143 // Creating and equipping Materia
144 if (src.get() && me.get()) {
145 AMateria *tmp = 0;
146
147 tmp = src->createMateria("ice");
148 if (tmp)
149 me->equip(tmp);
150
151 tmp = src->createMateria("cure");
152 if (tmp)
153 me->equip(tmp);
154 }
155
156 // Creating another ICharacter.(bob's interface)
157 bob.reset(new Character("bob"));
158
159 // Using Materia
160 if (me.get() && bob.get()) {
161 me->use(0, *bob);
162 me->use(1, *bob);
163 }
164
165 // No explicit delete required.
166 // delete bob;
167 // delete me;
168 // delete src;
169
170 } catch (const std::bad_alloc &e) {
171 LOG_ERROR("Memory allocation failed! " + std::string(e.what()));
172 // The destructor of the ScopedPointer is automatically called to ensure
173 // that the memory already allocated is freed.
174 return EXIT_FAILURE;
175 } catch (const std::exception &e) {
176 LOG_ERROR("An unexpected standard error occurred: " + std::string(e.what()));
177 return EXIT_FAILURE;
178 } catch (...) {
179 LOG_ERROR("An unknown error occurred.");
180 return EXIT_FAILURE;
181 }
182
183 // When the main function exits, the ScopedPointer objects of src, me, and bob exit scope.
184 // At that time, the respective destructor is called and the internal heap memory is released.
185 LOG_INFO("--- Program finished with ScopedPointer ---");
186 return 0;
187}
188
196static int testCharacterInventoryLimits(DroppedMateriaManager *droppedManager) {
197 LOG_INFO("\n--- Testing Character Inventory Limits ---");
198
199 // Automatically manage resources using ScopedPointer
200 // Even if new fails, the destructor of ScopedPointer is called
201 // Error handling when allocation fails can also be captured with Try-Catch
205
206 try {
207 alice.reset(new Character("alice"));
208 src.reset(new MateriaSource());
209
210 if (src.get()) {
211 src->learnMateria(new Ice());
212 src->learnMateria(new Cure());
213 }
214
215 // --- fill the inventory ---
216 if (alice.get() && src.get()) {
217 AMateria *tmp = 0;
218
219 tmp = src->createMateria("ice");
220 if (tmp)
221 alice->equip(tmp);
222
223 tmp = src->createMateria("cure");
224 if (tmp)
225 alice->equip(tmp);
226
227 tmp = src->createMateria("ice");
228 if (tmp)
229 alice->equip(tmp);
230
231 tmp = src->createMateria("cure");
232 if (tmp)
233 alice->equip(tmp);
234 }
235
236 // --- Attempt to equip a full inventory ---
237 if (alice.get()) {
238 // The materia created with new Ice() here is deleted within equip
239 // (assumed implementation of Character::equip).
240 alice->equip(new Ice());
241 }
242
243 // --- Use of Tests ---
244 bob.reset(new Character("bob"));
245
246 if (alice.get() && bob.get()) {
247 alice->use(0, *bob);
248 alice->use(1, *bob);
249 alice->use(2, *bob);
250 alice->use(3, *bob);
251 alice->use(4, *bob); // Invalid index
252 }
253
254 // --- Removing and dropping Materia ---
255 // getMateriaAtSlot does not transfer ownership, so
256 // the return value AMateria* unequipped_raw_ptr must be managed separately.
257 AMateria *unequipped_raw_ptr = 0;
258 if (alice.get()) {
259 unequipped_raw_ptr = alice->getMateriaAtSlot(1); // get pointer
260 alice->unequip(1); // remove from inventory
261 }
262
263 // Add discarded materia to the dropped manager.
264 // droppedManager->addMateria takes ownership (or deletes if it cannot be managed).
265 if (droppedManager && unequipped_raw_ptr) {
266 droppedManager->addMateria(unequipped_raw_ptr);
267 } else if (unequipped_raw_ptr) {
268 // If there is no drop manager, release it yourself (exceptional but safe).
269 LOG_WARNING("No droppedManager or null materia. Deleting unequipped materia directly.");
270 delete unequipped_raw_ptr;
271 }
272
273 } catch (const std::bad_alloc &e) {
274 LOG_ERROR("Memory allocation failed in testCharacterInventoryLimits! " + std::string(e.what()));
275 return EXIT_FAILURE;
276 } catch (const std::exception &e) {
277 LOG_ERROR("An unexpected standard error occurred in testCharacterInventoryLimits: " + std::string(e.what()));
278 return EXIT_FAILURE;
279 } catch (...) {
280 LOG_ERROR("An unknown error occurred in testCharacterInventoryLimits.");
281 return EXIT_FAILURE;
282 }
283 return 0;
284}
285
292static int testMateriaSourceLimits() {
293 LOG_INFO("\n--- Testing MateriaSource Learning Limits ---");
294
295 // IMateriaSource と ICharacter は ScopedPointer で管理
298
299 try {
300 src.reset(new MateriaSource());
301
302 // Teach Materia to MateriaSource
303 // ScopedPointer is not necessary, because learnMateria internally deletes the argument materia.
304 if (src.get()) {
305 src->learnMateria(new Ice());
306 src->learnMateria(new Cure());
307 src->learnMateria(new Ice());
308 src->learnMateria(new Cure());
309 }
310 std::cout << ">> MateriaSource should now be full <<" << std::endl;
311
312 // Attempting to learn more with a full MateriaSource
313 // Here, new is also deleted within learnMateria.
314 if (src.get()) {
315 src->learnMateria(new Ice());
316 }
317
318 // Creating ICharacter
319 me.reset(new Character("me"));
320
321 // Creating and equipping learned Materia
322 if (src.get() && me.get()) {
323 AMateria *tmp = 0;
324
325 tmp = src->createMateria("ice");
326 if (tmp)
327 me->equip(tmp);
328
329 tmp = src->createMateria("cure");
330 if (tmp)
331 me->equip(tmp);
332 }
333
334 // Test creating unknown Materia (should return NULL)
335 // new is not performed, so ScopedPointer is not necessary.
336 if (src.get() && me.get()) {
337 AMateria *tmp_unknown = 0;
338
339 tmp_unknown = src->createMateria("fire");
340 if (tmp_unknown == 0) {
341 LOG_INFO("Successfully tried to create unknown materia 'fire', returned NULL.");
342 } else {
343 LOG_ERROR("Creating unknown materia 'fire' returned non-NULL. Leaking materia.");
344 delete tmp_unknown;
345 }
346 }
347
348 } catch (const std::bad_alloc &e) {
349 LOG_ERROR("Memory allocation failed in testMateriaSourceLimits! " + std::string(e.what()));
350 return EXIT_FAILURE;
351 } catch (const std::exception &e) {
352 LOG_ERROR("An unexpected standard error occurred in testMateriaSourceLimits: " + std::string(e.what()));
353 return EXIT_FAILURE;
354 } catch (...) {
355 LOG_ERROR("An unknown error occurred in testMateriaSourceLimits.");
356 return EXIT_FAILURE;
357 }
358
359 LOG_INFO("--- Testing MateriaSource Learning Limits finished ---");
361 return 0;
362}
363
372static void testCharacterDeepCopy(DroppedMateriaManager *droppedManager) {
373
374 // --- Copy Constructor Test ---
375 std::cout << "\n--- Testing Deep Copy of Character ---" << std::endl;
376 Character charlie("charlie");
377 charlie.equip(new Ice());
378 charlie.equip(new Cure());
379
380 Character charlie_copy(charlie); // Test copy constructor
381
382 // Verify initial state and that equipping in original doesn't affect copy
383 std::cout << "Charlie's first materia type: " << charlie.getName() << " has "
384 << (charlie.isMateriaEquipped(0) ? charlie.getMateriaAtSlot(0)->getType() : "nothing") << " at slot 0"
385 << std::endl;
386 std::cout << "Charlie's copy's first materia type: " << charlie_copy.getName() << " has "
387 << (charlie_copy.isMateriaEquipped(0) ? charlie_copy.getMateriaAtSlot(0)->getType() : "nothing")
388 << " at slot 0" << std::endl;
389
390 AMateria *unequipped = charlie_copy.getMateriaAtSlot(0); // Get pointer before unequip
391 charlie_copy.unequip(0); // Modify the copy (unequip materia in slot 0)
392 droppedManager->addMateria(unequipped); // Drop Materia
393
394 // Original should be unchanged, demonstrating deep copy
395 std::cout << "After unequipping copy, Charlie's first materia type: " << charlie.getName() << " has "
396 << (charlie.isMateriaEquipped(0) ? charlie.getMateriaAtSlot(0)->getType() : "nothing") << " at slot 0"
397 << std::endl;
398 std::cout << "Charlie's copy's first materia type: " << charlie_copy.getName() << " has "
399 << (charlie_copy.isMateriaEquipped(0) ? charlie_copy.getMateriaAtSlot(0)->getType() : "nothing")
400 << " at slot 0" << std::endl;
401}
402
410static void testCharacterDeepCopyAssignment(DroppedMateriaManager *droppedManager) {
411
412 // --- Copy Assignment Operator Test ---
413 std::cout << "\n--- Testing Deep Copy Assignment of Character ---" << std::endl;
414 Character david("david");
415 david.equip(new Ice());
416 Character david_assigned("initial"); // Has initial state
417 david_assigned = david; // Use copy assignment operator
418
419 // Verify initial state after assignment
420 std::cout << "David's first materia type: " << david.getName() << " has "
421 << (david.isMateriaEquipped(0) ? david.getMateriaAtSlot(0)->getType() : "nothing") << " at slot 0"
422 << std::endl;
423 std::cout << "David's assigned's first materia type: " << david_assigned.getName() << " has "
424 << (david_assigned.isMateriaEquipped(0) ? david_assigned.getMateriaAtSlot(0)->getType() : "nothing")
425 << " at slot 0" << std::endl;
426
427 AMateria *unequipped = david_assigned.getMateriaAtSlot(0); // Get pointer before unequip
428 david_assigned.unequip(0); // Modify the assigned copy
429 droppedManager->addMateria(unequipped); // Drop Materia
430 std::cout << "After unequipping assigned, David's first materia type: " << david.getName() << " has "
431 << (david.isMateriaEquipped(0) ? david.getMateriaAtSlot(0)->getType() : "nothing") << " at slot 0"
432 << std::endl;
433 std::cout << "David's assigned's first materia type: " << david_assigned.getName() << " has "
434 << (david_assigned.isMateriaEquipped(0) ? david_assigned.getMateriaAtSlot(0)->getType() : "nothing")
435 << " at slot 0" << std::endl;
436}
437#endif // DEBUG_MODE
Declares the AMateria abstract base class.
Declares the Character class.
Declares the Cure materia class.
Declares the DroppedMateriaManager class.
Declares the ICharacter interface.
Declares the IMateriaSource interface.
Declares the Ice materia class.
Defines the Logger class for console-based logging.
#define LOG_WARNING(msg)
Macro for logging warning messages.
Definition Logger.hpp:85
#define LOG_ERROR(msg)
Definition Logger.hpp:93
#define LOG_INFO(msg)
Macro for logging informational messages.
Definition Logger.hpp:70
Declares the MateriaSource class.
Represents an abstract base class for all magical materias.
Definition AMateria.hpp:42
Represents a character capable of equipping and using Materias.
Definition Character.hpp:39
Represents a healing magic materia.
Definition Cure.hpp:36
Manages AMateria objects that are temporarily "dropped" in the game.
void displayDroppedMaterias() const
Displays the types and slots of all currently dropped materias for debugging.
void addMateria(AMateria *materia)
Adds a materia to the list of dropped materias. Takes ownership of the passed AMateria pointer....
An interface for any character that can interact with Materias.
virtual void use(int idx, ICharacter &target)=0
Uses the Materia at a specific inventory slot on a target character. This is a pure virtual function,...
virtual void equip(AMateria *m)=0
Equips a Materia to the character's inventory. This is a pure virtual function, requiring derived cla...
An interface for objects that can learn Materia templates and create new Materias.
virtual void learnMateria(AMateria *)=0
Learns a Materia template for later creation. This is a pure virtual function, requiring derived clas...
virtual AMateria * createMateria(std::string const &type) const =0
Creates a new Materia based on a learned type. This is a pure virtual function, requiring derived cla...
Represents an ice-based offensive magic materia.
Definition Ice.hpp:36
Represents a source for learning and creating Materias.
void reset(T *ptr=0)
T * get() const
T endl(T... args)
int main()
Main function of the program.
Definition main.cpp:35
ScopedPointer Class is Custom smart pointer with RAII pattern applied.
T what(T... args)