이 코드는 C++에서 가상 함수, 상속, 그리고 다형성의 개념을 설명하기 위한 예제입니다. 코드를 한 줄씩 분석하고 주석을 통해 상세히 설명하겠습니다.
Character
클래스 정의#pragma once
#include <iostream>
class Character
{
private:
int _health;
int _power;
Character
: 기본 캐릭터 클래스로, health
와 power
라는 두 개의 private 멤버 변수를 가집니다.public:
Character(int headth, int power)
: _health(headth), _power(power)
{
}
health
와 power
를 인자로 받아 초기화합니다. virtual ~Character()
{
std::cout << "~Character" << std::endl;
}
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;
}
};
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
객체 b
와 Derived
객체 d
를 생성합니다. b.nonVirtualFunc(); // Base
d.nonVirtualFunc(); // Derived
nonVirtualFunc
는 컴파일 타임에 결정되어, 각각 "nonVirtual Base"와 "nonVirtual Derived"를 출력합니다. b.virtualFunc(); // Base
d.virtualFunc(); // Derived
Base& b0 = d;
b0.nonVirtualFunc(); // Base
b0.virtualFunc(); // Derived
b0
는 Derived
객체를 가리키지만 타입은 Base
입니다.nonVirtualFunc
: 컴파일 타임에 결정되어 "nonVirtual Base"를 출력합니다.virtualFunc
: 런타임에 결정되어 "virtual Derived"를 출력합니다. Base* b1 = &d;
b1->nonVirtualFunc(); // Base
b1->virtualFunc(); // Derived
b1
은 Derived
객체를 가리키지만 타입은 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);
Player
와 Monster
객체 생성 및 공격:monster.attack(player)
는 Player
의 damaged
함수를 호출하여 "으악"을 출력합니다.player.attack(monster)
는 Monster
의 damaged
함수를 호출하여 "꿰엑"을 출력합니다. Character* ch = new Player(100, 10);
delete ch;
}
Character
포인터로 Player
객체를 생성합니다.delete
를 통해 소멸 시, 먼저 Player
소멸자가 호출되고, 이어서 Character
소멸자가 호출됩니다.이 코드는 C++의 가상 함수와 다형성 개념을 잘 설명합니다. 가상 함수는 객체의 실제 타입에 따라 호출될 함수가 결정되며, 비가상 함수는 컴파일 타임에 결정된다는 것을 보여줍니다. 또한, 동적 할당된 객체의 소멸자 호출 순서도 중요하게 다루어집니다.