第2章:課題の実装
はじめに
本章では、CPP Module 03の各演習を実装します。
---
1. ex00: Aaaaand... OPEN!
1.1 課題の要件
- ClapTrapクラスを作成
- 属性: name, hitPoints(10), energyPoints(10), attackDamage(0)
- attack, takeDamage, beRepairedメソッド
1.2 実装
// ClapTrap.hpp
#ifndef CLAPTRAP_HPP
#define CLAPTRAP_HPP
#include <string>
#include <iostream>
class ClapTrap {
protected:
std::string _name;
int _hitPoints;
int _energyPoints;
int _attackDamage;
public:
ClapTrap();
ClapTrap(const std::string& name);
ClapTrap(const ClapTrap& other);
ClapTrap& operator=(const ClapTrap& other);
~ClapTrap();
void attack(const std::string& target);
void takeDamage(unsigned int amount);
void beRepaired(unsigned int amount);
// ゲッター(デバッグ用)
std::string getName() const;
int getHitPoints() const;
int getEnergyPoints() const;
int getAttackDamage() const;
};
#endif
// ClapTrap.cpp
#include "ClapTrap.hpp"
ClapTrap::ClapTrap()
: _name("Unknown"), _hitPoints(10), _energyPoints(10), _attackDamage(0) {
std::cout << "ClapTrap default constructor called" << std::endl;
}
ClapTrap::ClapTrap(const std::string& name)
: _name(name), _hitPoints(10), _energyPoints(10), _attackDamage(0) {
std::cout << "ClapTrap constructor called for " << name << std::endl;
}
ClapTrap::ClapTrap(const ClapTrap& other)
: _name(other._name),
_hitPoints(other._hitPoints),
_energyPoints(other._energyPoints),
_attackDamage(other._attackDamage) {
std::cout << "ClapTrap copy constructor called" << std::endl;
}
ClapTrap& ClapTrap::operator=(const ClapTrap& other) {
std::cout << "ClapTrap copy assignment operator called" << std::endl;
if (this != &other) {
_name = other._name;
_hitPoints = other._hitPoints;
_energyPoints = other._energyPoints;
_attackDamage = other._attackDamage;
}
return *this;
}
ClapTrap::~ClapTrap() {
std::cout << "ClapTrap destructor called for " << _name << std::endl;
}
void ClapTrap::attack(const std::string& target) {
if (_hitPoints <= 0) {
std::cout << "ClapTrap " << _name << " is dead and cannot attack!" << std::endl;
return;
}
if (_energyPoints <= 0) {
std::cout << "ClapTrap " << _name << " has no energy to attack!" << std::endl;
return;
}
_energyPoints--;
std::cout << "ClapTrap " << _name << " attacks " << target
<< ", causing " << _attackDamage << " points of damage!" << std::endl;
}
void ClapTrap::takeDamage(unsigned int amount) {
_hitPoints -= amount;
if (_hitPoints < 0)
_hitPoints = 0;
std::cout << "ClapTrap " << _name << " takes " << amount
<< " points of damage! HP: " << _hitPoints << std::endl;
}
void ClapTrap::beRepaired(unsigned int amount) {
if (_hitPoints <= 0) {
std::cout << "ClapTrap " << _name << " is dead and cannot repair!" << std::endl;
return;
}
if (_energyPoints <= 0) {
std::cout << "ClapTrap " << _name << " has no energy to repair!" << std::endl;
return;
}
_energyPoints--;
_hitPoints += amount;
std::cout << "ClapTrap " << _name << " repairs itself for " << amount
<< " HP! HP: " << _hitPoints << std::endl;
}
std::string ClapTrap::getName() const { return _name; }
int ClapTrap::getHitPoints() const { return _hitPoints; }
int ClapTrap::getEnergyPoints() const { return _energyPoints; }
int ClapTrap::getAttackDamage() const { return _attackDamage; }
// main.cpp
#include "ClapTrap.hpp"
int main() {
ClapTrap a("Robot");
ClapTrap b("Droid");
a.attack("Droid");
b.takeDamage(0);
b.beRepaired(5);
// エネルギー消費テスト
for (int i = 0; i < 10; i++) {
a.attack("target");
}
a.attack("target"); // エネルギー切れ
return 0;
}
---
2. ex01: Serena, my love!
2.1 課題の要件
2.2 実装
// ScavTrap.hpp
#ifndef SCAVTRAP_HPP
#define SCAVTRAP_HPP
#include "ClapTrap.hpp"
class ScavTrap : public ClapTrap {
public:
ScavTrap();
ScavTrap(const std::string& name);
ScavTrap(const ScavTrap& other);
ScavTrap& operator=(const ScavTrap& other);
~ScavTrap();
void attack(const std::string& target);
void guardGate();
};
#endif
// ScavTrap.cpp
#include "ScavTrap.hpp"
ScavTrap::ScavTrap() : ClapTrap() {
_hitPoints = 100;
_energyPoints = 50;
_attackDamage = 20;
std::cout << "ScavTrap default constructor called" << std::endl;
}
ScavTrap::ScavTrap(const std::string& name) : ClapTrap(name) {
_hitPoints = 100;
_energyPoints = 50;
_attackDamage = 20;
std::cout << "ScavTrap constructor called for " << name << std::endl;
}
ScavTrap::ScavTrap(const ScavTrap& other) : ClapTrap(other) {
std::cout << "ScavTrap copy constructor called" << std::endl;
}
ScavTrap& ScavTrap::operator=(const ScavTrap& other) {
std::cout << "ScavTrap copy assignment operator called" << std::endl;
if (this != &other) {
ClapTrap::operator=(other);
}
return *this;
}
ScavTrap::~ScavTrap() {
std::cout << "ScavTrap destructor called for " << _name << std::endl;
}
void ScavTrap::attack(const std::string& target) {
if (_hitPoints <= 0) {
std::cout << "ScavTrap " << _name << " is dead and cannot attack!" << std::endl;
return;
}
if (_energyPoints <= 0) {
std::cout << "ScavTrap " << _name << " has no energy to attack!" << std::endl;
return;
}
_energyPoints--;
std::cout << "ScavTrap " << _name << " attacks " << target
<< ", causing " << _attackDamage << " points of damage!" << std::endl;
}
void ScavTrap::guardGate() {
std::cout << "ScavTrap " << _name << " is now in Gate keeper mode!" << std::endl;
}
// main.cpp
#include "ClapTrap.hpp"
#include "ScavTrap.hpp"
int main() {
std::cout << "=== Creating ClapTrap ===" << std::endl;
ClapTrap clap("Clappy");
std::cout << "\n=== Creating ScavTrap ===" << std::endl;
ScavTrap scav("Scavvy");
std::cout << "\n=== Actions ===" << std::endl;
clap.attack("Enemy");
scav.attack("Enemy");
scav.guardGate();
std::cout << "\n=== Destruction ===" << std::endl;
return 0;
}
2.3 期待される出力
=== Creating ClapTrap ===
ClapTrap constructor called for Clappy
=== Creating ScavTrap ===
ClapTrap constructor called for Scavvy
ScavTrap constructor called for Scavvy
=== Actions ===
ClapTrap Clappy attacks Enemy, causing 0 points of damage!
ScavTrap Scavvy attacks Enemy, causing 20 points of damage!
ScavTrap Scavvy is now in Gate keeper mode!
=== Destruction ===
ScavTrap destructor called for Scavvy
ClapTrap destructor called for Scavvy
ClapTrap destructor called for Clappy
---
3. ex02: Repetitive work
3.1 課題の要件
3.2 実装
// FragTrap.hpp
#ifndef FRAGTRAP_HPP
#define FRAGTRAP_HPP
#include "ClapTrap.hpp"
class FragTrap : public ClapTrap {
public:
FragTrap();
FragTrap(const std::string& name);
FragTrap(const FragTrap& other);
FragTrap& operator=(const FragTrap& other);
~FragTrap();
void highFivesGuys();
};
#endif
// FragTrap.cpp
#include "FragTrap.hpp"
FragTrap::FragTrap() : ClapTrap() {
_hitPoints = 100;
_energyPoints = 100;
_attackDamage = 30;
std::cout << "FragTrap default constructor called" << std::endl;
}
FragTrap::FragTrap(const std::string& name) : ClapTrap(name) {
_hitPoints = 100;
_energyPoints = 100;
_attackDamage = 30;
std::cout << "FragTrap constructor called for " << name << std::endl;
}
FragTrap::FragTrap(const FragTrap& other) : ClapTrap(other) {
std::cout << "FragTrap copy constructor called" << std::endl;
}
FragTrap& FragTrap::operator=(const FragTrap& other) {
std::cout << "FragTrap copy assignment operator called" << std::endl;
if (this != &other) {
ClapTrap::operator=(other);
}
return *this;
}
FragTrap::~FragTrap() {
std::cout << "FragTrap destructor called for " << _name << std::endl;
}
void FragTrap::highFivesGuys() {
std::cout << "FragTrap " << _name << " requests a high five!" << std::endl;
}
// main.cpp
#include "ClapTrap.hpp"
#include "ScavTrap.hpp"
#include "FragTrap.hpp"
int main() {
std::cout << "=== Creating Traps ===" << std::endl;
ClapTrap clap("Clappy");
ScavTrap scav("Scavvy");
FragTrap frag("Fraggy");
std::cout << "\n=== Actions ===" << std::endl;
clap.attack("Enemy");
scav.attack("Enemy");
scav.guardGate();
frag.attack("Enemy");
frag.highFivesGuys();
std::cout << "\n=== Destruction ===" << std::endl;
return 0;
}
---
4. ex03: Now it's weird!(Bonus)
4.1 課題の要件
4.2 仮想継承の修正
まず、ScavTrapとFragTrapを仮想継承に変更:
// ScavTrap.hpp
class ScavTrap : virtual public ClapTrap {
// ...
};
// FragTrap.hpp
class FragTrap : virtual public ClapTrap {
// ...
};
4.3 DiamondTrapの実装
// DiamondTrap.hpp
#ifndef DIAMONDTRAP_HPP
#define DIAMONDTRAP_HPP
#include "ScavTrap.hpp"
#include "FragTrap.hpp"
class DiamondTrap : public ScavTrap, public FragTrap {
private:
std::string _name;
public:
DiamondTrap();
DiamondTrap(const std::string& name);
DiamondTrap(const DiamondTrap& other);
DiamondTrap& operator=(const DiamondTrap& other);
~DiamondTrap();
void whoAmI();
using ScavTrap::attack; // ScavTrapのattackを使用
};
#endif
// DiamondTrap.cpp
#include "DiamondTrap.hpp"
DiamondTrap::DiamondTrap()
: ClapTrap("Unknown_clap_name"),
ScavTrap("Unknown"),
FragTrap("Unknown"),
_name("Unknown") {
_hitPoints = FragTrap::_hitPoints; // 100
_energyPoints = ScavTrap::_energyPoints; // 50
_attackDamage = FragTrap::_attackDamage; // 30
std::cout << "DiamondTrap default constructor called" << std::endl;
}
DiamondTrap::DiamondTrap(const std::string& name)
: ClapTrap(name + "_clap_name"),
ScavTrap(name),
FragTrap(name),
_name(name) {
_hitPoints = 100; // FragTrapから
_energyPoints = 50; // ScavTrapから
_attackDamage = 30; // FragTrapから
std::cout << "DiamondTrap constructor called for " << name << std::endl;
}
DiamondTrap::DiamondTrap(const DiamondTrap& other)
: ClapTrap(other),
ScavTrap(other),
FragTrap(other),
_name(other._name) {
std::cout << "DiamondTrap copy constructor called" << std::endl;
}
DiamondTrap& DiamondTrap::operator=(const DiamondTrap& other) {
std::cout << "DiamondTrap copy assignment operator called" << std::endl;
if (this != &other) {
ClapTrap::operator=(other);
_name = other._name;
}
return *this;
}
DiamondTrap::~DiamondTrap() {
std::cout << "DiamondTrap destructor called for " << _name << std::endl;
}
void DiamondTrap::whoAmI() {
std::cout << "I am DiamondTrap " << _name
<< ", also known as ClapTrap " << ClapTrap::_name << std::endl;
}
// main.cpp
#include "DiamondTrap.hpp"
int main() {
std::cout << "=== Creating DiamondTrap ===" << std::endl;
DiamondTrap diamond("Diamond");
std::cout << "\n=== DiamondTrap Info ===" << std::endl;
std::cout << "HP: " << diamond.getHitPoints() << std::endl; // 100
std::cout << "EP: " << diamond.getEnergyPoints() << std::endl; // 50
std::cout << "AD: " << diamond.getAttackDamage() << std::endl; // 30
std::cout << "\n=== Actions ===" << std::endl;
diamond.attack("Enemy"); // ScavTrapのattack
diamond.guardGate(); // ScavTrapのメソッド
diamond.highFivesGuys(); // FragTrapのメソッド
diamond.whoAmI(); // DiamondTrap独自
std::cout << "\n=== Destruction ===" << std::endl;
return 0;
}
4.4 コンストラクタ呼び出し順序
DiamondTrap生成時の順序:
- ClapTrap(仮想基底クラス、最初)
- ScavTrap
- FragTrap
- DiamondTrap
デストラクタは逆順:
- DiamondTrap
- FragTrap
- ScavTrap
- ClapTrap
4.5 期待される出力
=== Creating DiamondTrap ===
ClapTrap constructor called for Diamond_clap_name
ScavTrap constructor called for Diamond
FragTrap constructor called for Diamond
DiamondTrap constructor called for Diamond
=== DiamondTrap Info ===
HP: 100
EP: 50
AD: 30
=== Actions ===
ScavTrap Diamond attacks Enemy, causing 30 points of damage!
ScavTrap Diamond is now in Gate keeper mode!
FragTrap Diamond requests a high five!
I am DiamondTrap Diamond, also known as ClapTrap Diamond_clap_name
=== Destruction ===
DiamondTrap destructor called for Diamond
FragTrap destructor called for Diamond
ScavTrap destructor called for Diamond
ClapTrap destructor called for Diamond_clap_name
---
まとめ
本章で実装した内容: