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