이 코드는 C++에서 가상 함수, 상속, 그리고 다형성의 개념을 설명하기 위한 예제입니다. 코드를 한 줄씩 분석하고 주석을 통해 상세히 설명하겠습니다.

Character 클래스 정의

#pragma once

#include <iostream>

class Character
{
private:
    int _health;
    int _power;
  • 클래스 Character: 기본 캐릭터 클래스로, healthpower라는 두 개의 private 멤버 변수를 가집니다.
public:
    Character(int headth, int power)
        : _health(headth), _power(power)
    {

    }
  • 생성자: healthpower를 인자로 받아 초기화합니다.
    virtual ~Character()
    {
        std::cout << "~Character" << std::endl;
    }
  • 가상 소멸자: 자식 클래스의 소멸자를 올바르게 호출하기 위해 가상 소멸자로 선언되었습니다. 소멸 시 "Character" 메시지를 출력합니다.
    virtual void damaged(int power)
    {
        _health -= power;
    }
  • 가상 함수 damaged: power만큼 health를 감소시키는 함수로, 자식 클래스에서 오버라이드될 수 있습니다.
    void attack(Character& target) const
    {
        target.damaged(_power);
    }
  • attack 함수: 상대방 캐릭터의 damaged 함수를 호출하여 공격을 가합니다. 상수 메서드이므로 멤버 변수를 변경하지 않습니다.

Player 클래스 정의

class Player : public Character
{
public:
    using Character::Character;
    virtual void damaged(int power) override
    {
        Character::damaged(power);
        std::cout << "으악" << std::endl;
    }
  • Player 클래스: Character 클래스를 상속받은 클래스입니다.
  • using Character::Character;: 부모 클래스의 생성자를 그대로 사용합니다.
  • damaged 함수 오버라이드: 부모의 damaged 함수에 추가로 "으악"이라는 메시지를 출력합니다.
    virtual ~Player()
    {
        std::cout << "~Player" << std::endl;
    }
};
  • 소멸자: 소멸 시 "Player" 메시지를 출력합니다. 가상 소멸자로 선언되어 있어 올바르게 호출됩니다.

Monster 클래스 정의

class Monster : public Character
{
public:
    using Character::Character;
    virtual void damaged(int power) override
    {
        Character::damaged(power);
        std::cout << "꿰엑" << std::endl;
    }
};
  • Monster 클래스: Character 클래스를 상속받은 클래스입니다.
  • damaged 함수 오버라이드: 부모의 damaged 함수에 추가로 "꿰엑"이라는 메시지를 출력합니다.

Base 클래스 정의

class Base
{
public:
    virtual void virtualFunc()
    {
        cout << "virtual Base" << endl;
    }

    void nonVirtualFunc()
    {
        cout << "nonVirtual Base" << endl;
    }
};
  • Base 클래스: 기본 클래스입니다.
  • 가상 함수 virtualFunc: 가상 함수로 선언되어 있어 자식 클래스에서 오버라이드될 수 있습니다.
  • nonVirtualFunc: 일반 함수로, 오버라이드가 아닌 "숨김"이 발생할 수 있습니다.

Derived 클래스 정의

class Derived : public Base
{
public:
    virtual void virtualFunc() override
    {
        cout << "virtual Derived" << endl;
    }

    void nonVirtualFunc()
    {
        cout << "nonVirtual Derived" << endl;
    }
};
  • Derived 클래스: Base 클래스를 상속받습니다.
  • virtualFunc 오버라이드: 가상 함수 virtualFunc를 오버라이드하여 "virtual Derived"를 출력합니다.
  • nonVirtualFunc 함수 숨김: nonVirtualFunc을 동일한 이름으로 선언하여 부모의 함수를 숨깁니다. 이는 "오버라이드"가 아니라 "함수 숨김"입니다.

Derived1 클래스 정의

class Derived1 : public Derived
{
public:
    virtual void virtualFunc() override
    {
        cout << "virtual Derived1" << endl;
    }
};
  • Derived1 클래스: Derived 클래스를 상속받습니다.
  • virtualFunc 오버라이드: virtualFunc를 다시 오버라이드하여 "virtual Derived1"을 출력합니다.

foo 함수 정의

void foo(Base& base)
{
    base.virtualFunc();
}
  • foo 함수: Base 타입의 참조자를 받아 virtualFunc를 호출합니다. 객체가 어떤 실제 타입을 가지고 있는지에 따라 호출되는 함수가 달라집니다.

main 함수

int main()
{
    Base b;
    Derived d;
  • 객체 생성: Base 객체 bDerived 객체 d를 생성합니다.
    b.nonVirtualFunc(); // Base
    d.nonVirtualFunc(); // Derived
  • 비가상 함수 호출: nonVirtualFunc는 컴파일 타임에 결정되어, 각각 "nonVirtual Base"와 "nonVirtual Derived"를 출력합니다.
    b.virtualFunc(); // Base
    d.virtualFunc(); // Derived
  • 가상 함수 호출: 객체의 실제 타입에 따라, 각각 "virtual Base"와 "virtual Derived"를 출력합니다.
    Base& b0 = d;
    b0.nonVirtualFunc(); // Base
    b0.virtualFunc(); // Derived
  • 객체의 참조자 사용: b0Derived 객체를 가리키지만 타입은 Base입니다.
    • nonVirtualFunc: 컴파일 타임에 결정되어 "nonVirtual Base"를 출력합니다.
    • virtualFunc: 런타임에 결정되어 "virtual Derived"를 출력합니다.
    Base* b1 = &d;
    b1->nonVirtualFunc(); // Base
    b1->virtualFunc(); // Derived
  • 포인터 사용: b1Derived 객체를 가리키지만 타입은 Base 포인터입니다.
    • nonVirtualFunc: 컴파일 타임에 결정되어 "nonVirtual Base"를 출력합니다.
    • virtualFunc: 런타임에 결정되어 "virtual Derived"를 출력합니다.
    foo(b); // Base
    foo(d); // Derived
  • foo 함수 호출:
    • foo(b)는 "virtual Base"를 출력하고,
    • foo(d)는 "virtual Derived"를 출력합니다.
    Player player(100, 10);
    Monster monster(200, 20);

    monster.attack(player);
    player.attack(monster);
  • PlayerMonster 객체 생성 및 공격:
    • monster.attack(player)Playerdamaged 함수를 호출하여 "으악"을 출력합니다.
    • player.attack(monster)Monsterdamaged 함수를 호출하여 "꿰엑"을 출력합니다.
    Character* ch = new Player(100, 10);
    delete ch;
}
  • 동적 할당 및 소멸:
    • Character 포인터로 Player 객체를 생성합니다.
    • delete를 통해 소멸 시, 먼저 Player 소멸자가 호출되고, 이어서 Character 소멸자가 호출됩니다.

이 코드는 C++의 가상 함수와 다형성 개념을 잘 설명합니다. 가상 함수는 객체의 실제 타입에 따라 호출될 함수가 결정되며, 비가상 함수는 컴파일 타임에 결정된다는 것을 보여줍니다. 또한, 동적 할당된 객체의 소멸자 호출 순서도 중요하게 다루어집니다.

profile
李家네_공부방

0개의 댓글