CPP-Module-03

MELIES·2025년 2월 25일

Inheritance

1. ClapTrap 클래스 구현 (ex00)

class ClapTrap
{
private:
    std::string _name;

    unsigned int _hitPoints;
    unsigned int _energyPoints;
    unsigned int _attackDamage;

public:
    ClapTrap();
    ClapTrap(std::string name);
    ClapTrap(const ClapTrap &obj);
    ClapTrap &operator=(const ClapTrap &obj);
    ~ClapTrap();
    void attack(const std::string &target);
    void takeDamage(unsigned int amount);
    void beRepaired(unsigned int amount);
};

멤버 변수 접근자 변경

//ClapTrap.hpp
private:
    std::string _name;

    unsigned int _hitPoints;
    unsigned int _energyPoints;
    unsigned int _attackDamage;
//ClapTrap.hpp
protected:
    std::string _name;

    unsigned int _hitPoints;
    unsigned int _energyPoints;
    unsigned int _attackDamage;
  • private 대신 protected 사용해 파생 클래스에서 접근 가능하도록 설정

2. ScavTrap 클래스 구현 (ex01)

ClapTrap 클래스 상속

class ScavTrap : public ClapTrap
{
public:
    ScavTrap();
    ScavTrap(std::string name);
    ScavTrap(const ScavTrap &obj);
    ScavTrap &operator=(const ScavTrap &obj);
    ~ScavTrap();

    void attack(const std::string &target);
    void guardGate();
};

공통 기능을 부모 클래스에 구현해서 상속하고 특화된 기능을 자식 클래스에 추가

추가 함수
guardGate(): Gate keeper 모드 활성화 메시지 출력
attack() 함수는 다른 메시지를 출력하도록 오버라이딩 -> 같은 attack() 메서드라도 각 클래스에서 다르게 동작함

void ClapTrap::attack(const std::string &target)
{
    if (_hitPoints == 0)
    {
        std::cout << "ClapTrap " << _name << " has already died" << std::endl;
    }
    else if (_energyPoints == 0)
    {
        std::cout << "ClapTrap " << _name << " has no energy to attack!" << std::endl;
    }
    else
    {
        std::cout << "ClapTrap " << _name << " attacks " << target << ", causing " << _attackDamage << " points of damage!" << std::endl;
        _energyPoints--;
    }
}

void ScavTrap::attack(const std::string &target)
{
    if (_hitPoints == 0)
    {
        std::cout << "ScavTrap " << _name << " has already died." << std::endl;
    }
    else if (_energyPoints == 0)
    {
        std::cout << "ScavTrap " << _name << " has no energy to attack!" << std::endl;
    }
    else
    {
        std::cout << "ScavTrap " << _name << " attacks " << target << ", causing " << _attackDamage << " points of damage!" << std::endl;
        _energyPoints--;
    }
}

3. FragTrap 클래스 구현 (ex02)

ClapTrap 클래스 상속

class FragTrap : public ClapTrap
{
public:
    FragTrap();
    FragTrap(std::string name);
    FragTrap(const FragTrap &obj);
    FragTrap &operator=(const FragTrap &other);
    ~FragTrap();

    void highFivesGuys();
};

추가 함수
highFivesGuys(): positive high fives 요청 메시지 출력

void FragTrap::highFivesGuys()
{
    if (_hitPoints == 0)
    {
        std::cout << "FragTrap " << _name << " has already died" << std::endl;
    }
    else if (_energyPoints == 0)
    {
        std::cout << "FragTrap " << _name << " has no energy to high-five!" << std::endl;
    }
    else
    {
        _energyPoints--;
        std::cout << "FragTrap " << _name << " says : make some high-five!" << std::endl;
    }
}

Test

int main() {
    ClapTrap clapTrap("apple");
    ScavTrap ScavTrap("pineapple");
    FragTrap FragTrap("Flume");

    std::cout << std::endl;
    clapTrap.attack("banana");
    clapTrap.takeDamage(3);
    clapTrap.beRepaired(2);
    clapTrap.takeDamage(9);
    std::cout << std::endl;

    ScavTrap.attack("banana");
    ScavTrap.guardGate();
    ScavTrap.attack("banana");
    ScavTrap.takeDamage(100);
    ScavTrap.beRepaired(2);
    std::cout << std::endl;

    FragTrap.attack("banana");
    FragTrap.highFivesGuys();
    FragTrap.takeDamage(100);
    FragTrap.beRepaired(2);
    std::cout << std::endl;

    return 0;
}
ClapTrap apple is born!                 // ClapTrap 객체 생성
ScavTrap pineapple is born!             // ScavTrap 객체 생성
FragTrap Flume is born!                 // FragTrap 객체 생성

ClapTrap apple attacks banana, causing 0 points of damage!    // 공격력 0으로 공격
apple is taking 3 damage.               // 3 데미지를 입음 (HP: 10→7)
ClapTrap apple is repaired 2 hit points. Remaining hit points: 9    // 체력 회복 (HP: 7→9)
ClapTrap apple has died.                // 9 데미지를 더 입어 사망 (HP: 9→0)

ScavTrap pineapple attacks banana, causing 20 points of damage!    // 공격력 20으로 공격
ScavTrap pineapple has entered Gate keeper mode.    // 고유 기능 사용
ScavTrap pineapple attacks banana, causing 20 points of damage!    // 다시 공격
ScavTrap pineapple has died.            // 100 데미지를 입어 사망 (HP: 100→0)
ScavTrap pineapple has already died.    // 사망 상태에서 회복 시도 실패

FragTrap Flume attacks banana, causing 30 points of damage!    // 공격력 30으로 공격
FragTrap Flume says : make some high-five!    // 고유 기능 사용
FragTrap Flume has died.                // 100 데미지를 입어 사망 (HP: 100→0)
FragTrap Flume has already died.        // 사망 상태에서 회복 시도 실패

FragTrap Flume is destroyed!            // 소멸자 호출 (역순)
ScavTrap pineapple is destroyed!        // 소멸자 호출
ClapTrap apple is destroyed!            // 소멸자 호출

생성자 소멸자 동작 순서

생성자 동작 순서
부모 클래스 생성자 -> 자식 클래스 생성자
소멸자 동작 순서
자식 클래스 소멸자 -> 부모 클래스 소멸자

생성자 체이닝 (Constructor Chaining)

초기화 리스트를 이용해 명시적으로 호출

ScavTrap::ScavTrap(std::string name) : ClapTrap(name) {
    _name = name;
    _hitPoints = 100;
    _energyPoints = 50;
    _attackDamage = 20;
    std::cout << "ScavTrap " << _name << " is born!" << std::endl;
}
  • 만약 이 부분을 생략하면 부모 클래스의 기본 생성자(ClapTrap())가 자동으로 호출
    - 부모 클래스에 기본 생성자가 없는 경우 특정 매개변수를 받는 생성자를 호출하고 싶을 때는 이렇게 명시적으로 호출해야함

상속

  1. public 상속: 자식 클래스의 멤버 함수와 변수들이 부모 클래스의 접근 지정자에 맞게 상속
    • public 멤버는 public으로
    • protected 멤버는 protected
    • private 멤버는 자식 클래스에서 접근할 수 없으므로 상속되지 않음
  2. protected 상속: 자식 클래스의 멤버 함수와 변수들이 부모 클래스의 접근 지정자에 맞게 상속
    • public 멤버는 protected로 상속
    • protected 멤버는 protected로
    • private 멤버는 자식 클래스에서 접근할 수 없으므로 상속되지 않음
  3. private 상속: 자식 클래스의 멤버 함수와 변수들이 부모 클래스의 접근 지정자에 맞게 상속
    • public 멤버는 private으로 상속
    • protected 멤버는 private으로
    • private 멤버는 자식 클래스에서 접근할 수 없으므로 상속되지 않음

따라서, 부모 클래스의 생성자가 private인 경우 자식 클래스에서 해당 생성자를 호출하는 것은 불가능하다. 생성자는 외부에서 직접 호출되지 않고 객체를 생성할 때 자동으로 호출되기 때문이다. 상속 받더라도 private 생성자는 자식 클래스에서 사용할 수 없다.

profile
42 Seoul

0개의 댓글