CPP04 1.0
読み取り中…
検索中…
一致する文字列を見つけられません
C++ Module 04

Overview

このモジュールでは「ポリモーフィズム」の基礎から応用へと段階的に学習を深めていく課題です。

EX00: "Polymorphism" - ポリモーフィズム(多態性)の基本

‍ 異なる種類の動物を作る。

鳴き声が異なる。

基底クラス Animal は具体的な動物の鳴き声を発することができませんが、派生クラス Dog, Cat だとそれぞれ独自の音を出すことができる。

Animal Cat Dog
Generic animal sound Meow! Woof!

ポリモーフィズムの基本的な仕組みを使って、これを実現する。(基底クラス、派生クラス、仮想関数)

また、仮想関数を使わなかった場合( WrongAnimal, WrongCat )の動作がも理解できる。

EX01: "I don’t want to set the world on fire" - 世界を燃やしたくない

‍「Deep Copy」の概念を学ぶ課題です。

Brain クラスを作成して、Dog と Cat のメンバーにポインター Brain* を持たせます。

浅いコピー「Shallow Copy」と深いコピー「Deep Copy」の違いを理解し、クラス設計にDeep Copy を保証することで重大なメモリエラーを防ぐことができます。

堅牢なC++の基本要件として実践練習します。

EX02: "Abstract class" - 抽象クラス

‍EX00とEX01で作成した Animal クラスを「 抽象クラス 」にする課題です。

抽象クラスだけでのインスタンス化できない基底クラスであり、 CatDog の共通のインターフェースを 純粋仮想関数 として宣言することで、派生クラスに特定の振る舞い( makeSound() )を強制する仕組みを学びます。

EX03: "Interface & recap" - インターフェースと総括

‍総括としての課題として、特に「 インターフェース 」の概念(C++98において純粋仮想関数のみを持つ抽象クラス)を用いた設計を実践する課題です。

魔法使いがいるゲーム世界観を実装することになります。 魔法 Materia という概念があり、具体的な魔法として IceCure が存在します。 これらの魔法は MateriaSource の魔法テンプレートから生成され、魔法使い Character が装備して使うことができます。 ICharacterIMateriaSource といった「インターフェース」は、魔法使いや魔法の源がどのように振る舞うべきかの「契約」を定義します。 この物語を通して、抽象クラス (純粋仮想関数のみを持つ) をインターフェースとして利用し、異なるクラス ( Character , MateriaSource ) が共通のインターフェースを通して連携し、多態的な振る舞い ( use() 関数など) を実現する方法を学びます。 また、魔法使いが魔法をコピーしたり ( clone() )、インベントリで管理したりする中で、深いコピーやメモリ管理の重要性が再び強調されます。

まとめ

‍EX00 から EX03 を順番に取り組むことで、ポリモーフィズムという抽象的な概念が、具体的な動物の鳴き声から始まり、オブジェクトの内部構造、抽象的な概念、そしてより複雑なオブジェクト間の関係性へと、段階的に理解を深めていくことができます。

Project Links

‍Doxygenで作成されたソースコードドキュメントです。

クラスの連携図やソースコードの説明に関する情報がまとめられています。


課題を始める前に

オブジェクト指向プログラミング(OOP)の基本的な概念

‍ ポリモーフィズムは、OOPの三大要素(継承、カプセル化、ポリモーフィズム)の1つ。

C++ の言語仕様

‍ 仮想関数、抽象クラス、インターフェースといったポリモーフィズムを実現するための C++ の言語機能を学習し使いこなせるようになるための課題です。

-> **Interface とは?**

実践的な課題

‍ 動物の鳴き声(ex00~ex02 )、魔法のアイテムとその使用者(ex03)

これらの例は、ゲーム開発やシミュレーションなどの分野でポリモーフィズムが実際に活用されています。

抽象的な概念をより身近な問題に落とし込まれた課題内容です。

段階的な理解

‍ ポリモーフィズム → 抽象クラス → インターフェース

それぞれの仕組みを課題を通して理解していきます。

42 のカリキュラム

‍ CPP Modules 前半の課題で唯一経験値に直結する課題です。


ex00 "Polymorphism"

Class : Animal, Dog, Cat

Files :

Animal.hpp , Animal.cpp ,

Cat.hpp , Cat.cpp ,

Dog.hpp , Dog.cpp ,

WrongAnimal.hpp , WrongAnimal.cpp ,

WrongCat.hpp , WrongCat.cpp ,

main.cpp , Makefile ,

内容:

  • 基底クラス Animal から、派生クラス Cat, Dog を作る。

    ‍独自の鳴き声を派生クラスでは仮想関数を使って makeSound() を実装する。

    * 仮想関数を使わないケース:派生クラス WrongCat.hpp の makeSound() 定義に virtual を付けない。

    ‍WrongCat.cpp 独自の関数 makeSound() が呼ばれない。

キーワード、メモ:

Animal.hpp と WrongAnimal.hpp を分ける必要性がある?

基底クラスのポインタを使ったポリモーフィズム:シナリオ1

const Animal *j = new Dog();
const Animal *i = new Cat();
std::cout << j->getType() << " " << std::endl;
std::cout << i->getType() << " " << std::endl;
i->makeSound(); //will output the cat sound!
j->makeSound();
The Animal class represents a generic animal.
Definition Animal.hpp:37
const std::string & getType() const
Gets the type of the animal.
Definition Animal.cpp:72
virtual void makeSound() const
Makes a generic animal sound. This implementation is for the base Animal class. Derived classes are e...
Definition Animal.cpp:66
The Cat class represents a feline animal.
Definition Cat.hpp:33
The Dog class represents a canine animal.
Definition Dog.hpp:33
T endl(T... args)

これは派生オブジェクトを基底クラスのポインタとして宣言されている。

  • ポリモーフィズムの有効化

    ‍オブジェクトのポインターを使って仮想関数を呼び出すと、オブジェクトの型によって呼び出される関数が決まる。

    ランタイムポリモーフィズム Runtime polymorphism を実現することができる。(動的バインディングdynamic binding or 遅延バインディングlate binding)

    * 共通インターフェース

    ‍Animalのインターフェースを使えば、異なるオブジェクトの操作を共通のコードで行うことができる。

    Animalポインタを操作する汎用的なコード

    * 派生クラスの固有メンバーへのアクセス制限

    const Animal *j を通じて、Animalクラスで定義されたメンバーにのみアクセスできる。(Animalのpublic/protectedのメンバー)

    Dog固有のメソッドを(Dog::bark())使うためには、 dynamic_cast が必要。

    Dog* actualDog = dynamic_cast<Dog*>(j);
    if (actualDog) {
    actualDog->bark(); // Only possible after casting
    }
    void bark() const
    Makes a specific barking sound for a Dog. This is a Dog-specific method.
    Definition Dog.cpp:88
    * 仮想デストラクタの重要性

    ‍オブジェクトを削除は、 Dog::~Dog()Animal::~Animal() の順に呼び出す必要がある。

    Animalクラスに仮想デストラクタ(virtual ~Animal();)を持たせることで、派生クラス固有のリソースでのメモリリークを防ぐことができる。

派生クラスポインタを使ったを使った場合:シナリオ2

const Dog *j = new Dog(); // Pointer to Dog, points to a Dog object
const Cat *i = new Cat(); // Pointer to Cat, points to a Cat object
j->makeSound(); // Calls Dog::makeSound() -> "Woof!" (Compiler knows j is a Dog*)
i->makeSound(); // Calls Cat::makeSound() -> "Meow!" (Compiler knows i is a Cat*)
virtual void makeSound() const
Makes the characteristic sound of a cat ("Meow!"). This function overrides the virtual makeSound() fr...
Definition Cat.cpp:65
virtual void makeSound() const
Makes the characteristic sound of a dog ("Woof!"). This function overrides the virtual makeSound() fr...
Definition Dog.cpp:65

派生オブジェクトを指すポインタは、派生クラス正確な型のポインタを宣言している。

  • ポリモーフィズムなし

    ‍コンパイルの時点でオブジェクトの正確な型が決まっている。

  • 仮想関数の決定

    ‍ポインタの型がオブジェクトの型と一致するため、コンパイル時に呼び出される関数が決まる。

  • 全ての派生メンバーへのアクセス

    // If Dog had a specific bark() method:
    j->bark(); // Directly accessible

    派生クラス固有のメソッドを含む public / protect のメンバーに直接アクセスできる。

  • 柔軟性が低いコード

    // Example: an array (not possible with different derived types directly)
    const Dog* animals[2]; // Error: Cannot put a Cat* into a Dog* array

    1つの配列にグループ化することができない。

    (DogやCatを1つの配列やコレクションにまとめられない)

  • デストラクタの挙動

    ‍派生クラスポインタを使ってオブジェクトを削除する場合、 Animal::~Animal() が仮想かに関係なく、常に正しいデストラクタ Dog::~Dog() / Cat::~Cat() が最初に呼ばれる。

    なぜ?→コンパイラが削除されるオブジェクトの正確な型を認識しているため。

まとめると

‍基底クラスのポインタを使った最初のシナリオは、ポリモーフィズムの効果が発揮することができる。

複数の異なる派生オブジェクトをコレクションしたり、それらの操作するコードを共通化でき、それぞれ独自の関数は実行時に自動的に呼び出される。

結果、柔軟性が高く、保守性の高いオブジェクト指向システムを構築するための基礎となる考え方です。

動作結果

main.cpp
#include "Animal.hpp"
#include "Cat.hpp"
#include "Dog.hpp"
#include "WrongAnimal.hpp"
#include "WrongCat.hpp"
#include <iostream>
int main() {
// Polymorphism
regularPolymorphism();
// More in Animal
// More in WrongAnimal
return 0;
}
void wrongAnimalCopyConstAndAssignment(void)
Definition Tests.cpp:226
void wrongAnimalRegularTests(void)
Definition Tests.cpp:143
int wrongPolymorphism(void)
Definition Tests.cpp:27
int wrongAnimalArraySounds(void)
Definition Tests.cpp:157
void animalRegularTests(void)
Definition Tests.cpp:81
int animalArraySounds(void)
Definition Tests.cpp:100
void animalCopyConstAndAssignment(void)
Definition Tests.cpp:129
int main()
Main function of the program.
Definition main.cpp:35
static void regularPolymorphism(void) {
std::cout << "--- Regular Polymorphism ---" << std::endl;
// Create Animal, Dog, and Cat objects using base class pointers
const Animal *meta = new Animal();
const Animal *j = new Dog();
const Animal *i = new Cat();
// Demonstrate getType() access
std::cout << j->getType() << " " << std::endl;
std::cout << i->getType() << " " << std::endl;
// Demonstrate makeSound() behavior (polymorphic dispatch for Dog and Cat)
i->makeSound(); // output : "Meow!"
j->makeSound(); // output : "Woof!"
meta->makeSound(); // output : "Generic animal sound"
// Clean up
delete meta;
delete j;
delete i;
}
static void wrongPolymorphism(void) {
std::cout << "--- Wrong Polymorphism ---" << std::endl;
// Create WrongAnimal and WrongCat objects using base class pointers
const WrongAnimal *wrongMeta = new WrongAnimal();
const WrongAnimal *wrongJ = new WrongCat();
// Demonstrate getType() access (works fine as it's not virtual behavior being tested)
std::cout << wrongJ->getType() << " " << std::endl;
// Demonstrate makeSound() behavior (NO polymorphic dispatch for WrongCat)
wrongJ->makeSound(); // "Wrong generic animal sound"
wrongMeta->makeSound(); // "Wrong generic animal sound"
// Clean up dynamically allocated objects
delete wrongMeta;
delete wrongJ;
}
The WrongAnimal class represents a generic animal, used to demonstrate the LACK of polymorphism when ...
const std::string & getType() const
Gets the type of the WrongAnimal.
void makeSound() const
Makes a generic sound for a WrongAnimal. This function is intentionally NOT VIRTUAL to show the lack ...
The WrongCat class represents a feline animal in the "wrong" hierarchy.
Definition WrongCat.hpp:34
static void animalRegularTests(void) {
std::cout << "--- Animal Regular Tests ---" << std::endl;
// Test objects created on the stack to see constructor/destructor calls
Animal basicAnimal;
Dog basicDog;
Cat basicCat;
// Call getType() and makeSound() on stack objects
std::cout << basicAnimal.getType() << " " << std::endl;
std::cout << basicDog.getType() << " " << std::endl;
std::cout << basicCat.getType() << " " << std::endl;
basicAnimal.makeSound();
basicDog.makeSound();
basicCat.makeSound();
}
static void animalArraySounds(void) {
// Test polymorphic array
Animal *animalArray[4];
animalArray[0] = new Dog();
animalArray[1] = new Cat();
animalArray[2] = new Dog();
animalArray[3] = new Cat();
std::cout << "\n--- Animal Array Sounds ---" << std::endl;
for (int k = 0; k < 4; ++k) {
std::cout << animalArray[k]->getType() << " says: ";
animalArray[k]->makeSound(); // Polymorphic call
}
// Clean up array elements
for (int k = 0; k < 4; ++k) {
delete animalArray[k]; // Virtual destructor ensures proper cleanup
}
}
static void animalCopyConstAndAssignment(void) {
std::cout << "--- Copy Constructor and Assignment (Regular) ---" << std::endl;
Dog anotherDog;
Dog yetAnotherDog(anotherDog); // Copy constructor
Cat anotherCat;
Cat yetAnotherCat;
yetAnotherCat = anotherCat; // Copy assignment operator
std::cout << anotherDog.getType() << " copied to " << yetAnotherDog.getType() << std::endl;
std::cout << anotherCat.getType() << " assigned to " << yetAnotherCat.getType() << std::endl;
}
static void wrongAnimalRegularTests(void) {
std::cout << "--- More Tests (Wrong) ---" << std::endl;
// Test wrong objects on the stack
WrongAnimal basicWrongAnimal;
WrongCat basicWrongCat;
std::cout << basicWrongAnimal.getType() << " " << std::endl;
std::cout << basicWrongCat.getType() << " " << std::endl;
basicWrongAnimal.makeSound();
basicWrongCat.makeSound();
}
void makeSound() const
Makes the characteristic sound of a WrongCat ("Wrong meow!").
Definition WrongCat.cpp:73
static void wrongAnimalArraySounds(void) {
// Test wrong polymorphic array
WrongAnimal *wrongAnimalArray[2];
wrongAnimalArray[0] = new WrongCat();
wrongAnimalArray[1] = new WrongCat();
std::cout << "--- Wrong Animal Array Sounds ---" << std::endl;
for (int l = 0; l < 2; ++l) {
std::cout << wrongAnimalArray[l]->getType() << " says: ";
wrongAnimalArray[l]->makeSound(); // Will output WrongAnimal sound (static binding)
}
// Clean up wrong array elements
for (int l = 0; l < 2; ++l) {
delete wrongAnimalArray[l];
}
}
std::cout << "--- Copy Constructor and Assignment (Wrong) ---" << std::endl;
WrongCat anotherWrongCat;
// Copy constructor
WrongCat yetAnotherWrongCat(anotherWrongCat);
WrongAnimal yetAnotherWrongAnimal;
// Note: Assignment of WrongCat to WrongAnimal (slicing might occur if not careful with ownership)
yetAnotherWrongAnimal = anotherWrongCat;
std::cout << anotherWrongCat.getType() << " copied to " << yetAnotherWrongCat.getType() << std::endl;
std::cout << yetAnotherWrongCat.getType() << " assigned to " << yetAnotherWrongAnimal.getType() << std::endl;
// Will output WrongAnimal sound due to static binding on WrongAnimal object
yetAnotherWrongAnimal.makeSound();
}
出力
$ ./a.out
--- Regular Polymorphism ---
Animal default constructor called
Animal default constructor called
Dog default constructor called
Animal default constructor called
Cat default constructor called
Dog
Cat
Meow!
Woof!
Generic animal sound
Animal destructor called
Dog destructor called
Animal destructor called
Cat destructor called
Animal destructor called
--- Wrong Polymorphism ---
WrongAnimal default constructor called
WrongAnimal default constructor called
WrongCat default constructor called
WrongCat
Wrong generic animal sound
Wrong generic animal sound
WrongAnimal destructor called
WrongCat destructor called
WrongAnimal destructor called
--- Animal Regular Tests ---
Animal default constructor called
Animal default constructor called
Dog default constructor called
Animal default constructor called
Cat default constructor called
Generic Animal
Dog
Cat
Generic animal sound
Woof!
Meow!
Cat destructor called
Animal destructor called
Dog destructor called
Animal destructor called
Animal destructor called
Animal default constructor called
Dog default constructor called
Animal default constructor called
Cat default constructor called
Animal default constructor called
Dog default constructor called
Animal default constructor called
Cat default constructor called
--- Animal Array Sounds ---
Dog says: Woof!
Cat says: Meow!
Dog says: Woof!
Cat says: Meow!
Dog destructor called
Animal destructor called
Cat destructor called
Animal destructor called
Dog destructor called
Animal destructor called
Cat destructor called
Animal destructor called
--- Copy Constructor and Assignment (Regular) ---
Animal default constructor called
Dog default constructor called
Animal copy constructor called
Dog copy constructor called
Animal default constructor called
Cat default constructor called
Animal default constructor called
Cat default constructor called
Cat copy assignment operator called
Animal copy assignment operator called
Dog copied to Dog
Cat assigned to Cat
Cat destructor called
Animal destructor called
Cat destructor called
Animal destructor called
Dog destructor called
Animal destructor called
Dog destructor called
Animal destructor called
--- More Tests (Wrong) ---
WrongAnimal default constructor called
WrongAnimal default constructor called
WrongCat default constructor called
Generic WrongAnimal
WrongCat
Wrong generic animal sound
Wrong meow!
WrongCat destructor called
WrongAnimal destructor called
WrongAnimal destructor called
WrongAnimal default constructor called
WrongCat default constructor called
WrongAnimal default constructor called
WrongCat default constructor called
--- Wrong Animal Array Sounds ---
WrongCat says: Wrong generic animal sound
WrongCat says: Wrong generic animal sound
WrongCat destructor called
WrongAnimal destructor called
WrongCat destructor called
WrongAnimal destructor called
--- Copy Constructor and Assignment (Wrong) ---
WrongAnimal default constructor called
WrongCat default constructor called
WrongAnimal copy constructor called
WrongCat copy constructor called
WrongAnimal default constructor called
WrongAnimal copy assignment operator called
WrongCat copied to WrongCat
WrongCat assigned to WrongCat
Wrong generic animal sound
WrongAnimal destructor called
WrongCat destructor called
WrongAnimal destructor called
WrongCat destructor called
WrongAnimal destructor called

ex01 "I don’t want to set the world on fire"

Class : Brain

Files :

Animal.hpp , Animal.cpp ,

Brain.hpp , Brain.cpp , ← 追加

Cat.hpp , Cat.cpp ,

Dog.hpp , Dog.cpp ,

WrongAnimal.hpp , WrongAnimal.cpp ,

WrongCat.hpp , WrongCat.cpp ,

main.cpp , Makefile ,

内容:

‍* Brain クラス:

‍100個の std::string 型の配列を含む。

setIdea()getIdea() メソッドを追加

* DogBrain の改良

‍コンストラクタでは Brain オブジェクトを動的に生成する。

デストラクタで適切に delete することでメモリリークを防ぐ。

また、コピーコンストラクタとコピー代入演算子を実装する。(Deep Copy)

キーワード、メモ:

‍* 動的メモリ割り当て(new, delete)

  • ポインタによるオブジェクトの管理
  • メモリリークの防止
  • 深いコピー(Deep Copy)と浅いコピー(Shallow Copy)
  • コピーコンストラクタ、コピー代入演算子
  • デストラクタ(基底デストラクタが virtual であることが重要)
  • 基底クラスポインタによる派生クラスオブジェクトの配列管理
  • ポリモーフィズムによるデストラクタの呼び出し

動作結果

main.cpp
#include "Animal.hpp"
#include "Brain.hpp"
#include "Cat.hpp"
#include "Dog.hpp"
#include "WrongAnimal.hpp"
#include "WrongCat.hpp"
#include <iostream>
static void basicTests(void) {
std::cout << "--- Basic Tests from Exercise ---" << std::endl;
const Animal *j = new Dog();
const Animal *i = new Cat();
delete j; // Should call Dog destructor then Brain destructor
delete i; // Should call Cat destructor then Brain destructor
}
static void arrayAnimals(void) {
std::cout << "\n--- Array of Animals ---" << std::endl;
Animal *animals[10];
for (int k = 0; k < 10; ++k) {
if (k < 5)
animals[k] = new Dog();
else
animals[k] = new Cat();
}
std::cout << "\n--- Making Sounds in Animal Array ---" << std::endl;
for (int k = 0; k < 10; ++k) {
std::cout << "Animal [" << k << "] (type: " << animals[k]->getType() << ") says: ";
animals[k]->makeSound();
}
std::cout << "\n--- Deleting Animals in Array ---" << std::endl;
for (int k = 0; k < 10; ++k) {
delete animals[k]; // Polymorphic deletion: calls Dog or Cat destructor, then Brain destructor
}
}
static void deepCopyTests(void) {
std::cout << "\n--- Deep Copy Tests ---" << std::endl;
// Copy Constructor Test
Dog originalDog;
originalDog.getBrain()->setIdea(0, "Bone!");
Dog copiedDog = originalDog; // Using copy constructor
std::cout << "Original Dog's first idea: " << originalDog.getBrain()->getIdea(0) << std::endl;
std::cout << "Copied Dog's first idea: " << copiedDog.getBrain()->getIdea(0) << std::endl;
copiedDog.getBrain()->setIdea(0, "Squirrel!");
std::cout << "Original Dog's first idea after copied Dog changed: " << originalDog.getBrain()->getIdea(0)
std::cout << "Copied Dog's first idea after copied Dog changed: " << copiedDog.getBrain()->getIdea(0) << std::endl;
// Copy Assignment Operator Test
Cat originalCat;
originalCat.getBrain()->setIdea(0, "Fish!");
Cat assignedCat;
assignedCat = originalCat; // Using copy assignment operator
std::cout << "Original Cat's first idea: " << originalCat.getBrain()->getIdea(0) << std::endl;
std::cout << "Assigned Cat's first idea: " << assignedCat.getBrain()->getIdea(0) << std::endl;
assignedCat.getBrain()->setIdea(0, "Nap!");
std::cout << "Original Cat's first idea after assigned Cat changed: " << originalCat.getBrain()->getIdea(0)
std::cout << "Assigned Cat's first idea after assigned Cat changed: " << assignedCat.getBrain()->getIdea(0)
}
static void stackTests(void) {
std::cout << "\n--- More Tests (Stack Objects) ---" << std::endl;
{
Dog stackDog;
stackDog.getBrain()->setIdea(50, "Walkies?");
std::cout << "Stack Dog's 50th idea: " << stackDog.getBrain()->getIdea(50) << std::endl;
} // stackDog and its Brain are destroyed here
{
Cat stackCat;
stackCat.getBrain()->setIdea(99, "Laser pointer!");
std::cout << "Stack Cat's 99th idea: " << stackCat.getBrain()->getIdea(99) << std::endl;
} // stackCat and its Brain are destroyed here
}
int main() {
basicTests();
arrayAnimals();
deepCopyTests();
stackTests();
return 0;
}
const std::string & getIdea(int index) const
Gets an idea from a specific index in the brain. Performs bounds checking. If the index is out of bou...
Definition Brain.cpp:92
void setIdea(int index, const std::string &idea)
Sets an idea at a specific index in the brain. Performs bounds checking to ensure the index is valid ...
Definition Brain.cpp:80
Brain * getBrain() const
Gets a pointer to the Cat's Brain object.
Definition Cat.cpp:98
Brain * getBrain() const
Gets a pointer to the Dog's Brain object.
Definition Dog.cpp:94
出力
$ ./a.out
--- Basic Tests from Exercise ---
Animal default constructor called
Brain default constructor called
Dog default constructor called
Animal default constructor called
Brain default constructor called
Cat default constructor called
Brain destructor called
Dog destructor called
Animal destructor called
Brain destructor called
Cat destructor called
Animal destructor called
--- Array of Animals ---
Animal default constructor called
Brain default constructor called
Dog default constructor called
Animal default constructor called
Brain default constructor called
Dog default constructor called
Animal default constructor called
Brain default constructor called
Dog default constructor called
Animal default constructor called
Brain default constructor called
Dog default constructor called
Animal default constructor called
Brain default constructor called
Dog default constructor called
Animal default constructor called
Brain default constructor called
Cat default constructor called
Animal default constructor called
Brain default constructor called
Cat default constructor called
Animal default constructor called
Brain default constructor called
Cat default constructor called
Animal default constructor called
Brain default constructor called
Cat default constructor called
Animal default constructor called
Brain default constructor called
Cat default constructor called
--- Making Sounds in Animal Array ---
Animal [0] (type: Dog) says: Woof!
Animal [1] (type: Dog) says: Woof!
Animal [2] (type: Dog) says: Woof!
Animal [3] (type: Dog) says: Woof!
Animal [4] (type: Dog) says: Woof!
Animal [5] (type: Cat) says: Meow!
Animal [6] (type: Cat) says: Meow!
Animal [7] (type: Cat) says: Meow!
Animal [8] (type: Cat) says: Meow!
Animal [9] (type: Cat) says: Meow!
--- Deleting Animals in Array ---
Brain destructor called
Dog destructor called
Animal destructor called
Brain destructor called
Dog destructor called
Animal destructor called
Brain destructor called
Dog destructor called
Animal destructor called
Brain destructor called
Dog destructor called
Animal destructor called
Brain destructor called
Dog destructor called
Animal destructor called
Brain destructor called
Cat destructor called
Animal destructor called
Brain destructor called
Cat destructor called
Animal destructor called
Brain destructor called
Cat destructor called
Animal destructor called
Brain destructor called
Cat destructor called
Animal destructor called
Brain destructor called
Cat destructor called
Animal destructor called
--- Deep Copy Tests ---
Animal default constructor called
Brain default constructor called
Dog default constructor called
Animal copy constructor called
Dog copy constructor called
Brain copy constructor called
Original Dog's first idea: Bone!
Copied Dog's first idea: Bone!
Original Dog's first idea after copied Dog changed: Bone!
Copied Dog's first idea after copied Dog changed: Squirrel!
Animal default constructor called
Brain default constructor called
Cat default constructor called
Animal default constructor called
Brain default constructor called
Cat default constructor called
Cat copy assignment operator called
Animal copy assignment operator called
Brain copy assignment operator called
Original Cat's first idea: Fish!
Assigned Cat's first idea: Fish!
Original Cat's first idea after assigned Cat changed: Fish!
Assigned Cat's first idea after assigned Cat changed: Nap!
Brain destructor called
Cat destructor called
Animal destructor called
Brain destructor called
Cat destructor called
Animal destructor called
Brain destructor called
Dog destructor called
Animal destructor called
Brain destructor called
Dog destructor called
Animal destructor called
--- More Tests (Stack Objects) ---
Animal default constructor called
Brain default constructor called
Dog default constructor called
Stack Dog's 50th idea: Walkies?
Brain destructor called
Dog destructor called
Animal destructor called
Animal default constructor called
Brain default constructor called
Cat default constructor called
Stack Cat's 99th idea: Laser pointer!
Brain destructor called
Cat destructor called
Animal destructor called
覚え書き

ex02 "Abstract class"

Files :

Animal.hpp , Animal.cpp , ← 更新

Brain.hpp , Brain.cpp ,

Cat.hpp , Cat.cpp ,

Dog.hpp , Dog.cpp ,

WrongAnimal.hpp , WrongAnimal.cpp ,

WrongCat.hpp , WrongCat.cpp ,

main.cpp , Makefile ,

内容:

‍* Animal クラスを抽象化クラス( Abstract Class ) にする。

‍仕組み

‍純粋仮想関数( Pure Virtual Function )がクラス内に1つでも存在する場合、そのクラスは自動的に抽象的クラスになります。

抽象クラスでは実装せず、派生クラスの実装が義務付けられる。

効果:デフォルトの Animal クラスはインスタンス化できない。

Animal meta;new Animal(); はコンパイルエラーになる。

* EX00 と EX02 の Animal の違い

‍インスタンス化:

‍EX00 ... インスタンス化できた。

EX02 ... インスタンス化できない。

仮想関数( EX00 )・純粋仮想関数( EX02 )

virtual void makeSound() const; // EX00 仮想関数 :実装あり

virtual void makeSound() const = 0; // EX02 純粋仮想関数 :実装なし

DogCat の動物だけがインスタンス化でき、 makeSound() を提供することで、ポリモーフィズムがより強く強制される。

動作結果

main.cpp
#include "Animal.hpp" // Now abstract
#include "Brain.hpp"
#include "Cat.hpp"
#include "Dog.hpp"
#include "WrongAnimal.hpp"
#include "WrongCat.hpp"
#include <iostream>
static void polymorphismWithConcreateClasses(void) {
std::cout << "--- Testing Polymorphism with Concrete Classes ---" << std::endl;
const Animal *j = new Dog();
const Animal *i = new Cat();
std::cout << j->getType() << " " << std::endl;
std::cout << i->getType() << " " << std::endl;
j->makeSound();
i->makeSound();
delete j;
delete i;
}
static void arrayAnimals(void) {
std::cout << "\n--- Array of Animals (Concrete Types) ---" << std::endl;
Animal *animals[10];
for (int k = 0; k < 10; ++k) {
if (k < 5)
animals[k] = new Dog();
else
animals[k] = new Cat();
}
std::cout << "\n--- Making Sounds in Animal Array ---" << std::endl;
for (int k = 0; k < 10; ++k) {
std::cout << "Animal [" << k << "] (type: " << animals[k]->getType() << ") says: ";
animals[k]->makeSound();
}
std::cout << "\n--- Deleting Animals in Array ---" << std::endl;
for (int k = 0; k < 10; ++k) {
delete animals[k];
}
}
static void deepCopyTests(void) {
std::cout << "\n--- Deep Copy Tests (Still Valid) ---" << std::endl;
// Copy Constructor Test
Dog originalDog;
originalDog.getBrain()->setIdea(0, "Bone!");
Dog copiedDog = originalDog;
std::cout << "Original Dog's first idea: " << originalDog.getBrain()->getIdea(0) << std::endl;
std::cout << "Copied Dog's first idea: " << copiedDog.getBrain()->getIdea(0) << std::endl;
copiedDog.getBrain()->setIdea(0, "Squirrel!");
std::cout << "Original Dog's first idea after copied Dog changed: " << originalDog.getBrain()->getIdea(0)
std::cout << "Copied Dog's first idea after copied Dog changed: " << copiedDog.getBrain()->getIdea(0) << std::endl;
// Copy Assignment Operator Test
Cat originalCat;
originalCat.getBrain()->setIdea(0, "Fish!");
Cat assignedCat;
assignedCat = originalCat;
std::cout << "Original Cat's first idea: " << originalCat.getBrain()->getIdea(0) << std::endl;
std::cout << "Assigned Cat's first idea: " << assignedCat.getBrain()->getIdea(0) << std::endl;
assignedCat.getBrain()->setIdea(0, "Nap!");
std::cout << "Original Cat's first idea after assigned Cat changed: " << originalCat.getBrain()->getIdea(0)
std::cout << "Assigned Cat's first idea after assigned Cat changed: " << assignedCat.getBrain()->getIdea(0)
}
static void stackTests(void) {
std::cout << "\n--- More Tests (Stack Objects) ---" << std::endl;
{
Dog stackDog;
stackDog.getBrain()->setIdea(50, "Walkies?");
std::cout << "Stack Dog's 50th idea: " << stackDog.getBrain()->getIdea(50) << std::endl;
} // stackDog and its Brain are destroyed here
{
Cat stackCat;
stackCat.getBrain()->setIdea(99, "Laser pointer!");
std::cout << "Stack Cat's 99th idea: " << stackCat.getBrain()->getIdea(99) << std::endl;
} // stackCat and its Brain are destroyed here
}
int main() {
polymorphismWithConcreateClasses();
arrayAnimals();
deepCopyTests();
stackTests();
std::cout << "\n--- Attempting to Instantiate Animal (Should Fail at Compile Time) ---" << std::endl;
// The following line will now cause a compile-time error:
// Animal basicAnimal;
return 0;
}
出力
$ ./a.out
--- Testing Polymorphism with Concrete Classes ---
Animal default constructor called
Brain default constructor called
Dog default constructor called
Animal default constructor called
Brain default constructor called
Cat default constructor called
Dog
Cat
Woof!
Meow!
Brain destructor called
Dog destructor called
Animal destructor called
Brain destructor called
Cat destructor called
Animal destructor called
--- Array of Animals (Concrete Types) ---
Animal default constructor called
Brain default constructor called
Dog default constructor called
Animal default constructor called
Brain default constructor called
Dog default constructor called
Animal default constructor called
Brain default constructor called
Dog default constructor called
Animal default constructor called
Brain default constructor called
Dog default constructor called
Animal default constructor called
Brain default constructor called
Dog default constructor called
Animal default constructor called
Brain default constructor called
Cat default constructor called
Animal default constructor called
Brain default constructor called
Cat default constructor called
Animal default constructor called
Brain default constructor called
Cat default constructor called
Animal default constructor called
Brain default constructor called
Cat default constructor called
Animal default constructor called
Brain default constructor called
Cat default constructor called
--- Making Sounds in Animal Array ---
Animal [0] (type: Dog) says: Woof!
Animal [1] (type: Dog) says: Woof!
Animal [2] (type: Dog) says: Woof!
Animal [3] (type: Dog) says: Woof!
Animal [4] (type: Dog) says: Woof!
Animal [5] (type: Cat) says: Meow!
Animal [6] (type: Cat) says: Meow!
Animal [7] (type: Cat) says: Meow!
Animal [8] (type: Cat) says: Meow!
Animal [9] (type: Cat) says: Meow!
--- Deleting Animals in Array ---
Brain destructor called
Dog destructor called
Animal destructor called
Brain destructor called
Dog destructor called
Animal destructor called
Brain destructor called
Dog destructor called
Animal destructor called
Brain destructor called
Dog destructor called
Animal destructor called
Brain destructor called
Dog destructor called
Animal destructor called
Brain destructor called
Cat destructor called
Animal destructor called
Brain destructor called
Cat destructor called
Animal destructor called
Brain destructor called
Cat destructor called
Animal destructor called
Brain destructor called
Cat destructor called
Animal destructor called
Brain destructor called
Cat destructor called
Animal destructor called
--- Deep Copy Tests (Still Valid) ---
Animal default constructor called
Brain default constructor called
Dog default constructor called
Animal copy constructor called
Dog copy constructor called
Brain copy constructor called
Original Dog's first idea: Bone!
Copied Dog's first idea: Bone!
Original Dog's first idea after copied Dog changed: Bone!
Copied Dog's first idea after copied Dog changed: Squirrel!
Animal default constructor called
Brain default constructor called
Cat default constructor called
Animal default constructor called
Brain default constructor called
Cat default constructor called
Cat copy assignment operator called
Animal copy assignment operator called
Brain copy assignment operator called
Original Cat's first idea: Fish!
Assigned Cat's first idea: Fish!
Original Cat's first idea after assigned Cat changed: Fish!
Assigned Cat's first idea after assigned Cat changed: Nap!
Brain destructor called
Cat destructor called
Animal destructor called
Brain destructor called
Cat destructor called
Animal destructor called
Brain destructor called
Dog destructor called
Animal destructor called
Brain destructor called
Dog destructor called
Animal destructor called
--- More Tests (Stack Objects) ---
Animal default constructor called
Brain default constructor called
Dog default constructor called
Stack Dog's 50th idea: Walkies?
Brain destructor called
Dog destructor called
Animal destructor called
Animal default constructor called
Brain default constructor called
Cat default constructor called
Stack Cat's 99th idea: Laser pointer!
Brain destructor called
Cat destructor called
Animal destructor called
--- Attempting to Instantiate Animal (Should Fail at Compile Time) ---

ex03 "Interface & recap"

Class : AMateria Cure Ice IMaterialSource MateriaSource ICharacter Character

Files :

AMateria.hpp , AMateria.cpp ,

Ice.hpp , Ice.cpp ,

Cure.hpp , Cure.cpp ,

MateriaSource.hpp , MateriaSource.cpp ,

Character.hpp , Character.cpp ,

ICharacter.hpp , IMateriaSource.hpp , <- この2つがインターフェース

main.cpp , Makefile ,

内容:

AMateria という 抽象クラス を定義し、具体的な Materia の種類として IceCure クラスを実装します。

それぞれの Materia は Cure::clone() , Ice::clone() 関数で自身のコピーを生成し、 Cure::use() , Ice::use() 関数で特定の効果を発揮します。

また、ICharacter というインターフェースを定義し、それを実装する Character クラスを作成します。

Character は Materia を装備・装備解除・使用するためのインベントリを持ち、コピー時には深いコピーが行われるように設計します。

さらに、 IMateriaSource という インターフェース と、それを実装する MateriaSource クラスを作成し、Materia の「学習」と「生成」の仕組みを実装します。

セルフボーナスとして、 main 関数で各クラスを使う時のエラーハンドル(特に new 失敗に関する考え方やリソースを安全に解放すること)について学びました。

詳しくは、RAII ( Resource Acquisition Is Initialization ) にまとめます。

動作結果

main.cpp Basic Test
int main() {
src->learnMateria(new Ice());
src->learnMateria(new Cure());
ICharacter *me = new Character("me");
AMateria *tmp;
tmp = src->createMateria("ice");
me->equip(tmp);
tmp = src->createMateria("cure");
me->equip(tmp);
ICharacter *bob = new Character("bob");
me->use(0, *bob);
me->use(1, *bob);
delete bob;
delete me;
delete src;
return 0;
}
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
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.
出力 (Basic Test)
$ ./a.out
* shoots an ice bolt at bob *
* heals bob's wounds *
main.cpp More Test
#ifdef DEBUG_MODE
// Create instance DroppedMateriaManager
// This is the specific substance of the "system for managing dropped Materia.
DroppedMateriaManager droppedManager;
std::cout << "\n--- More Tests ---" << std::endl;
testBasicRaii();
testCharacterInventoryLimits(&droppedManager);
testMateriaSourceLimits();
testCharacterDeepCopy(&droppedManager);
testCharacterDeepCopyAssignment(&droppedManager);
droppedManager.displayDroppedMaterias(); // display current Dropped Mateias.
// don't have to call delete ( Because the destructor automatically calls clearAll().)
#endif // DEBUG_MODE
return 0;
}
// --- Helper Function Implementations ---
#ifdef DEBUG_MODE
static int testBasicRaii(void) {
LOG_INFO("--- Test Basic with ScopedPointer ---");
// ScopedPointer is placed on the stack and is automatically released when exiting scope.
try {
// Create Instance of IMateriaSource
src.reset(new MateriaSource()); // If new fails, throw bad_alloc
// Learn Materia : Materia *m->clone() and delete m are performed.
src->learnMateria(new Ice());
src->learnMateria(new Cure());
// I think better code support Owner Ship.
// It is desirable that the implementation of ‘new Icd()’ passed as an argument be owned by the caller.
// The code example is as follows.
// (however, this approach is not required for the assignment, so it will not be used).
// ******* example code ***********
// ScopedPointer<AMateria> ice_to_learn(new Ice()); // If new Ice() failed throw bad_alloc
// ScopedPointer<AMateria> cure_to_learn(new Cure()); // If new Cure() failed throw bad_alloc
// if (src.get()) {
// src->learnMateria(ice_to_learn.get()); // learnMateria does not take ownership
// src->learnMateria(cure_to_learn.get());
//}
// ******* code end ***********
// ice_to_learn and cure_to_learn are automatically released when exiting the scope.
// If learnMateria takes ownership (does not delete internally), it must be passed in release().
// current design: learnMateria clones, so passed materia is caller's responsibility.
// Create Instance ICharacter.(me's interface)
me.reset(new Character("me")); // If new Character() fails, throw bad_alloc.
// Creating and equipping Materia
if (src.get() && me.get()) {
AMateria *tmp = 0;
tmp = src->createMateria("ice");
if (tmp)
me->equip(tmp);
tmp = src->createMateria("cure");
if (tmp)
me->equip(tmp);
}
// Creating another ICharacter.(bob's interface)
bob.reset(new Character("bob"));
// Using Materia
if (me.get() && bob.get()) {
me->use(0, *bob);
me->use(1, *bob);
}
// No explicit delete required.
// delete bob;
// delete me;
// delete src;
} catch (const std::bad_alloc &e) {
LOG_ERROR("Memory allocation failed! " + std::string(e.what()));
// The destructor of the ScopedPointer is automatically called to ensure
// that the memory already allocated is freed.
return EXIT_FAILURE;
} catch (const std::exception &e) {
LOG_ERROR("An unexpected standard error occurred: " + std::string(e.what()));
return EXIT_FAILURE;
} catch (...) {
LOG_ERROR("An unknown error occurred.");
return EXIT_FAILURE;
}
// When the main function exits, the ScopedPointer objects of src, me, and bob exit scope.
// At that time, the respective destructor is called and the internal heap memory is released.
LOG_INFO("--- Program finished with ScopedPointer ---");
return 0;
}
static int testCharacterInventoryLimits(DroppedMateriaManager *droppedManager) {
LOG_INFO("\n--- Testing Character Inventory Limits ---");
// Automatically manage resources using ScopedPointer
// Even if new fails, the destructor of ScopedPointer is called
// Error handling when allocation fails can also be captured with Try-Catch
try {
alice.reset(new Character("alice"));
src.reset(new MateriaSource());
if (src.get()) {
src->learnMateria(new Ice());
src->learnMateria(new Cure());
}
// --- fill the inventory ---
if (alice.get() && src.get()) {
AMateria *tmp = 0;
tmp = src->createMateria("ice");
if (tmp)
alice->equip(tmp);
tmp = src->createMateria("cure");
if (tmp)
alice->equip(tmp);
tmp = src->createMateria("ice");
if (tmp)
alice->equip(tmp);
tmp = src->createMateria("cure");
if (tmp)
alice->equip(tmp);
}
// --- Attempt to equip a full inventory ---
if (alice.get()) {
// The materia created with new Ice() here is deleted within equip
// (assumed implementation of Character::equip).
alice->equip(new Ice());
}
// --- Use of Tests ---
bob.reset(new Character("bob"));
if (alice.get() && bob.get()) {
alice->use(0, *bob);
alice->use(1, *bob);
alice->use(2, *bob);
alice->use(3, *bob);
alice->use(4, *bob); // Invalid index
}
// --- Removing and dropping Materia ---
// getMateriaAtSlot does not transfer ownership, so
// the return value AMateria* unequipped_raw_ptr must be managed separately.
AMateria *unequipped_raw_ptr = 0;
if (alice.get()) {
unequipped_raw_ptr = alice->getMateriaAtSlot(1); // get pointer
alice->unequip(1); // remove from inventory
}
// Add discarded materia to the dropped manager.
// droppedManager->addMateria takes ownership (or deletes if it cannot be managed).
if (droppedManager && unequipped_raw_ptr) {
droppedManager->addMateria(unequipped_raw_ptr);
} else if (unequipped_raw_ptr) {
// If there is no drop manager, release it yourself (exceptional but safe).
LOG_WARNING("No droppedManager or null materia. Deleting unequipped materia directly.");
delete unequipped_raw_ptr;
}
} catch (const std::bad_alloc &e) {
LOG_ERROR("Memory allocation failed in testCharacterInventoryLimits! " + std::string(e.what()));
return EXIT_FAILURE;
} catch (const std::exception &e) {
LOG_ERROR("An unexpected standard error occurred in testCharacterInventoryLimits: " + std::string(e.what()));
return EXIT_FAILURE;
} catch (...) {
LOG_ERROR("An unknown error occurred in testCharacterInventoryLimits.");
return EXIT_FAILURE;
}
return 0;
}
static int testMateriaSourceLimits() {
LOG_INFO("\n--- Testing MateriaSource Learning Limits ---");
// IMateriaSource と ICharacter は ScopedPointer で管理
try {
src.reset(new MateriaSource());
// Teach Materia to MateriaSource
// ScopedPointer is not necessary, because learnMateria internally deletes the argument materia.
if (src.get()) {
src->learnMateria(new Ice());
src->learnMateria(new Cure());
src->learnMateria(new Ice());
src->learnMateria(new Cure());
}
std::cout << ">> MateriaSource should now be full <<" << std::endl;
// Attempting to learn more with a full MateriaSource
// Here, new is also deleted within learnMateria.
if (src.get()) {
src->learnMateria(new Ice());
}
// Creating ICharacter
me.reset(new Character("me"));
// Creating and equipping learned Materia
if (src.get() && me.get()) {
AMateria *tmp = 0;
tmp = src->createMateria("ice");
if (tmp)
me->equip(tmp);
tmp = src->createMateria("cure");
if (tmp)
me->equip(tmp);
}
// Test creating unknown Materia (should return NULL)
// new is not performed, so ScopedPointer is not necessary.
if (src.get() && me.get()) {
AMateria *tmp_unknown = 0;
tmp_unknown = src->createMateria("fire");
if (tmp_unknown == 0) {
LOG_INFO("Successfully tried to create unknown materia 'fire', returned NULL.");
} else {
LOG_ERROR("Creating unknown materia 'fire' returned non-NULL. Leaking materia.");
delete tmp_unknown;
}
}
} catch (const std::bad_alloc &e) {
LOG_ERROR("Memory allocation failed in testMateriaSourceLimits! " + std::string(e.what()));
return EXIT_FAILURE;
} catch (const std::exception &e) {
LOG_ERROR("An unexpected standard error occurred in testMateriaSourceLimits: " + std::string(e.what()));
return EXIT_FAILURE;
} catch (...) {
LOG_ERROR("An unknown error occurred in testMateriaSourceLimits.");
return EXIT_FAILURE;
}
LOG_INFO("--- Testing MateriaSource Learning Limits finished ---");
return 0;
}
static void testCharacterDeepCopy(DroppedMateriaManager *droppedManager) {
// --- Copy Constructor Test ---
std::cout << "\n--- Testing Deep Copy of Character ---" << std::endl;
Character charlie("charlie");
charlie.equip(new Ice());
charlie.equip(new Cure());
Character charlie_copy(charlie); // Test copy constructor
// Verify initial state and that equipping in original doesn't affect copy
std::cout << "Charlie's first materia type: " << charlie.getName() << " has "
<< (charlie.isMateriaEquipped(0) ? charlie.getMateriaAtSlot(0)->getType() : "nothing") << " at slot 0"
std::cout << "Charlie's copy's first materia type: " << charlie_copy.getName() << " has "
<< (charlie_copy.isMateriaEquipped(0) ? charlie_copy.getMateriaAtSlot(0)->getType() : "nothing")
<< " at slot 0" << std::endl;
AMateria *unequipped = charlie_copy.getMateriaAtSlot(0); // Get pointer before unequip
charlie_copy.unequip(0); // Modify the copy (unequip materia in slot 0)
droppedManager->addMateria(unequipped); // Drop Materia
// Original should be unchanged, demonstrating deep copy
std::cout << "After unequipping copy, Charlie's first materia type: " << charlie.getName() << " has "
<< (charlie.isMateriaEquipped(0) ? charlie.getMateriaAtSlot(0)->getType() : "nothing") << " at slot 0"
std::cout << "Charlie's copy's first materia type: " << charlie_copy.getName() << " has "
<< (charlie_copy.isMateriaEquipped(0) ? charlie_copy.getMateriaAtSlot(0)->getType() : "nothing")
<< " at slot 0" << std::endl;
}
static void testCharacterDeepCopyAssignment(DroppedMateriaManager *droppedManager) {
// --- Copy Assignment Operator Test ---
std::cout << "\n--- Testing Deep Copy Assignment of Character ---" << std::endl;
Character david("david");
david.equip(new Ice());
Character david_assigned("initial"); // Has initial state
david_assigned = david; // Use copy assignment operator
// Verify initial state after assignment
std::cout << "David's first materia type: " << david.getName() << " has "
<< (david.isMateriaEquipped(0) ? david.getMateriaAtSlot(0)->getType() : "nothing") << " at slot 0"
std::cout << "David's assigned's first materia type: " << david_assigned.getName() << " has "
<< (david_assigned.isMateriaEquipped(0) ? david_assigned.getMateriaAtSlot(0)->getType() : "nothing")
<< " at slot 0" << std::endl;
AMateria *unequipped = david_assigned.getMateriaAtSlot(0); // Get pointer before unequip
david_assigned.unequip(0); // Modify the assigned copy
droppedManager->addMateria(unequipped); // Drop Materia
std::cout << "After unequipping assigned, David's first materia type: " << david.getName() << " has "
<< (david.isMateriaEquipped(0) ? david.getMateriaAtSlot(0)->getType() : "nothing") << " at slot 0"
std::cout << "David's assigned's first materia type: " << david_assigned.getName() << " has "
<< (david_assigned.isMateriaEquipped(0) ? david_assigned.getMateriaAtSlot(0)->getType() : "nothing")
<< " at slot 0" << std::endl;
}
#endif // DEBUG_MODE
#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
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....
void reset(T *ptr=0)
T * get() const
T what(T... args)
出力 (More Test)
$ make test
$ ./a.out
[INFO] MateriaSource constructor called
[INFO] AMateria constructor called for type: ice
[INFO] Ice constructor called
[INFO] AMateria constructor called for type: ice
[INFO] Ice constructor called
[INFO] MateriaSource learned ice
[INFO] Ice destructor called
[INFO] AMateria destructor called for type: ice
[INFO] AMateria constructor called for type: cure
[INFO] Cure constructor called
[INFO] AMateria constructor called for type: cure
[INFO] Cure constructor called
[INFO] MateriaSource learned cure
[INFO] Cure destructor called
[INFO] AMateria destructor called for type: cure
[INFO] Character constructor called for me
[INFO] MateriaSource creates ice
[INFO] AMateria constructor called for type: ice
[INFO] Ice constructor called
[INFO] me equipped ice at slot 0
[INFO] MateriaSource creates cure
[INFO] AMateria constructor called for type: cure
[INFO] Cure constructor called
[INFO] me equipped cure at slot 1
[INFO] Character constructor called for bob
* shoots an ice bolt at bob *
* heals bob's wounds *
[INFO] Character destructor called for bob
[INFO] Character destructor called for me
[INFO] Ice destructor called
[INFO] AMateria destructor called for type: ice
[INFO] Cure destructor called
[INFO] AMateria destructor called for type: cure
[INFO] MateriaSource destructor called
[INFO] Ice destructor called
[INFO] AMateria destructor called for type: ice
[INFO] Cure destructor called
[INFO] AMateria destructor called for type: cure
[INFO] DroppedMateriaManager: Default constructor called.
--- More Tests ---
[INFO] --- Test Basic with ScopedPointer ---
ScopedPointer(0) created.
ScopedPointer(0) created.
ScopedPointer(0) created.
[INFO] MateriaSource constructor called
[INFO] AMateria constructor called for type: ice
[INFO] Ice constructor called
[INFO] AMateria constructor called for type: ice
[INFO] Ice constructor called
[INFO] MateriaSource learned ice
[INFO] Ice destructor called
[INFO] AMateria destructor called for type: ice
[INFO] AMateria constructor called for type: cure
[INFO] Cure constructor called
[INFO] AMateria constructor called for type: cure
[INFO] Cure constructor called
[INFO] MateriaSource learned cure
[INFO] Cure destructor called
[INFO] AMateria destructor called for type: cure
[INFO] Character constructor called for me
[INFO] MateriaSource creates ice
[INFO] AMateria constructor called for type: ice
[INFO] Ice constructor called
[INFO] me equipped ice at slot 0
[INFO] MateriaSource creates cure
[INFO] AMateria constructor called for type: cure
[INFO] Cure constructor called
[INFO] me equipped cure at slot 1
[INFO] Character constructor called for bob
* shoots an ice bolt at bob *
* heals bob's wounds *
[INFO] --- Program finished with ScopedPointer ---
ScopedPointer(0xaaab12a822b0) destroyed. Deleting resource.
[INFO] Character destructor called for bob
ScopedPointer(0xaaab12a82230) destroyed. Deleting resource.
[INFO] Character destructor called for me
[INFO] Ice destructor called
[INFO] AMateria destructor called for type: ice
[INFO] Cure destructor called
[INFO] AMateria destructor called for type: cure
ScopedPointer(0xaaab12a80eb0) destroyed. Deleting resource.
[INFO] MateriaSource destructor called
[INFO] Ice destructor called
[INFO] AMateria destructor called for type: ice
[INFO] Cure destructor called
[INFO] AMateria destructor called for type: cure
[INFO]
--- Testing Character Inventory Limits ---
ScopedPointer(0) created.
ScopedPointer(0) created.
ScopedPointer(0) created.
[INFO] Character constructor called for alice
[INFO] MateriaSource constructor called
[INFO] AMateria constructor called for type: ice
[INFO] Ice constructor called
[INFO] AMateria constructor called for type: ice
[INFO] Ice constructor called
[INFO] MateriaSource learned ice
[INFO] Ice destructor called
[INFO] AMateria destructor called for type: ice
[INFO] AMateria constructor called for type: cure
[INFO] Cure constructor called
[INFO] AMateria constructor called for type: cure
[INFO] Cure constructor called
[INFO] MateriaSource learned cure
[INFO] Cure destructor called
[INFO] AMateria destructor called for type: cure
[INFO] MateriaSource creates ice
[INFO] AMateria constructor called for type: ice
[INFO] Ice constructor called
[INFO] alice equipped ice at slot 0
[INFO] MateriaSource creates cure
[INFO] AMateria constructor called for type: cure
[INFO] Cure constructor called
[INFO] alice equipped cure at slot 1
[INFO] MateriaSource creates ice
[INFO] AMateria constructor called for type: ice
[INFO] Ice constructor called
[INFO] alice equipped ice at slot 2
[INFO] MateriaSource creates cure
[INFO] AMateria constructor called for type: cure
[INFO] Cure constructor called
[INFO] alice equipped cure at slot 3
[INFO] AMateria constructor called for type: ice
[INFO] Ice constructor called
[INFO] alice's inventory is full, cannot equip ice
[INFO] Ice destructor called
[INFO] AMateria destructor called for type: ice
[INFO] Character constructor called for bob
* shoots an ice bolt at bob *
* heals bob's wounds *
* shoots an ice bolt at bob *
* heals bob's wounds *
[INFO] alice tried to use invalid slot 4
[INFO] alice unequips cure from slot 1
[INFO] DroppedMateriaManager: Added cure at slot 0
ScopedPointer(0xaaab12a822b0) destroyed. Deleting resource.
[INFO] Character destructor called for bob
ScopedPointer(0xaaab12a80eb0) destroyed. Deleting resource.
[INFO] MateriaSource destructor called
[INFO] Ice destructor called
[INFO] AMateria destructor called for type: ice
[INFO] Cure destructor called
[INFO] AMateria destructor called for type: cure
ScopedPointer(0xaaab12a82230) destroyed. Deleting resource.
[INFO] Character destructor called for alice
[INFO] Ice destructor called
[INFO] AMateria destructor called for type: ice
[INFO] Ice destructor called
[INFO] AMateria destructor called for type: ice
[INFO] Cure destructor called
[INFO] AMateria destructor called for type: cure
[INFO]
--- Testing MateriaSource Learning Limits ---
ScopedPointer(0) created.
ScopedPointer(0) created.
[INFO] MateriaSource constructor called
[INFO] AMateria constructor called for type: ice
[INFO] Ice constructor called
[INFO] AMateria constructor called for type: ice
[INFO] Ice constructor called
[INFO] MateriaSource learned ice
[INFO] Ice destructor called
[INFO] AMateria destructor called for type: ice
[INFO] AMateria constructor called for type: cure
[INFO] Cure constructor called
[INFO] AMateria constructor called for type: cure
[INFO] Cure constructor called
[INFO] MateriaSource learned cure
[INFO] Cure destructor called
[INFO] AMateria destructor called for type: cure
[INFO] AMateria constructor called for type: ice
[INFO] Ice constructor called
[INFO] AMateria constructor called for type: ice
[INFO] Ice constructor called
[INFO] MateriaSource learned ice
[INFO] Ice destructor called
[INFO] AMateria destructor called for type: ice
[INFO] AMateria constructor called for type: cure
[INFO] Cure constructor called
[INFO] AMateria constructor called for type: cure
[INFO] Cure constructor called
[INFO] MateriaSource learned cure
[INFO] Cure destructor called
[INFO] AMateria destructor called for type: cure
>> MateriaSource should now be full <<
[INFO] AMateria constructor called for type: ice
[INFO] Ice constructor called
[INFO] MateriaSource cannot learn more materia.
[INFO] Ice destructor called
[INFO] AMateria destructor called for type: ice
[INFO] Character constructor called for me
[INFO] MateriaSource creates ice
[INFO] AMateria constructor called for type: ice
[INFO] Ice constructor called
[INFO] me equipped ice at slot 0
[INFO] MateriaSource creates cure
[INFO] AMateria constructor called for type: cure
[INFO] Cure constructor called
[INFO] me equipped cure at slot 1
[INFO] MateriaSource does not know materia type fire
[INFO] Successfully tried to create unknown materia 'fire', returned NULL.
[INFO] --- Testing MateriaSource Learning Limits finished ---
ScopedPointer(0xaaab12a82230) destroyed. Deleting resource.
[INFO] Character destructor called for me
[INFO] Ice destructor called
[INFO] AMateria destructor called for type: ice
[INFO] Cure destructor called
[INFO] AMateria destructor called for type: cure
ScopedPointer(0xaaab12a80eb0) destroyed. Deleting resource.
[INFO] MateriaSource destructor called
[INFO] Ice destructor called
[INFO] AMateria destructor called for type: ice
[INFO] Cure destructor called
[INFO] AMateria destructor called for type: cure
[INFO] Ice destructor called
[INFO] AMateria destructor called for type: ice
[INFO] Cure destructor called
[INFO] AMateria destructor called for type: cure
--- Testing Deep Copy of Character ---
[INFO] Character constructor called for charlie
[INFO] AMateria constructor called for type: ice
[INFO] Ice constructor called
[INFO] charlie equipped ice at slot 0
[INFO] AMateria constructor called for type: cure
[INFO] Cure constructor called
[INFO] charlie equipped cure at slot 1
[INFO] Character copy constructor called for charlie
[INFO] AMateria constructor called for type: ice
[INFO] Ice constructor called
[INFO] charlie equipped ice at slot 0
[INFO] AMateria constructor called for type: cure
[INFO] Cure constructor called
[INFO] charlie equipped cure at slot 1
Charlie's first materia type: charlie has ice at slot 0
Charlie's copy's first materia type: charlie has ice at slot 0
[INFO] charlie unequips ice from slot 0
[INFO] DroppedMateriaManager: Added ice at slot 1
After unequipping copy, Charlie's first materia type: charlie has ice at slot 0
Charlie's copy's first materia type: charlie has nothing at slot 0
[INFO] Character destructor called for charlie
[INFO] Cure destructor called
[INFO] AMateria destructor called for type: cure
[INFO] Character destructor called for charlie
[INFO] Ice destructor called
[INFO] AMateria destructor called for type: ice
[INFO] Cure destructor called
[INFO] AMateria destructor called for type: cure
--- Testing Deep Copy Assignment of Character ---
[INFO] Character constructor called for david
[INFO] AMateria constructor called for type: ice
[INFO] Ice constructor called
[INFO] david equipped ice at slot 0
[INFO] Character constructor called for initial
[INFO] Character copy assignment operator called for david
[INFO] AMateria constructor called for type: ice
[INFO] Ice constructor called
[INFO] david equipped ice at slot 0
David's first materia type: david has ice at slot 0
David's assigned's first materia type: david has ice at slot 0
[INFO] david unequips ice from slot 0
[INFO] DroppedMateriaManager: Added ice at slot 2
After unequipping assigned, David's first materia type: david has ice at slot 0
David's assigned's first materia type: david has nothing at slot 0
[INFO] Character destructor called for david
[INFO] Character destructor called for david
[INFO] Ice destructor called
[INFO] AMateria destructor called for type: ice
[INFO] DroppedMateriaManager: Currently dropped materias (3):
>> debug >> 3[0xaaab12a821d0]
- Slot 0: cure
>> debug >> 3[0xaaab12a82200]
- Slot 1: ice
>> debug >> 3[0xaaab12a81f90]
- Slot 2: ice
[INFO] DroppedMateriaManager: Destructor called. Clearing all dropped materias.
DroppedMateriaManager: Deleting remaining dropped materia cure at slot 0
[INFO] Cure destructor called
[INFO] AMateria destructor called for type: cure
DroppedMateriaManager: Deleting remaining dropped materia ice at slot 1
[INFO] Ice destructor called
[INFO] AMateria destructor called for type: ice
DroppedMateriaManager: Deleting remaining dropped materia ice at slot 2
[INFO] Ice destructor called
[INFO] AMateria destructor called for type: ice

Other

  • ブランチの使い方

    main: 安定版

    feature/ex00: 各課題の機能開発を行う。

    docs: ここにpushすると、GitHub Actions workflowが動作してドキュメントが公開されます。

  • ドキュメントページ

    ‍C++ Moduleのプロジェクト毎にDoxygenを使ったドキュメントをまとめています。

    doxygen用のcssテーマは、Doxygen Awesomeを使用。