void Move() { cout << "Move Player !" << endl; }
// 오버로딩
void Move(int a) { cout << "Move Player (int) !" << endl; }
void Move() { cout << "Move Player !" << endl; }
// 오버라이딩
void Move() { cout << "Move Player Overriding !" << endl; }
class Player
{
public:
void Move() { cout << "Move Player !" << endl; }
// 오버로딩
void Move(int a) { cout << "Move Player (int) !" << endl; }
};
class Knight : public Player
{
public:
// 오버라이딩
void Move() { cout << "Move Knight !" << endl; }
};
void MovePlayer(Player* player)
{
// 정적 바인딩 -> 컴파일타임에 결정
// Player 객체가 매개변수로 들어올 것으로 예상하고 있음.
// 매개변수에 Knight 객체가 들어와도 Player 클래스의 Move() 가 실행됨.
player->Move();
}
void MoveKnight(Knight* knight)
{
knight->Move();
}
int main()
{
Player p;
MovePlayer(&p); // 플레이어는 플레이어다? YES
// MoveKnight(&p); // 플레이어는 기사다? NO <- 꼭 그렇진 않을 것(Error!)
Knight k;
MoveKnight(&k); // 기사는 기사다? YES
MovePlayer(&k); // 기사는 플레이어다? YES <- 기사이기 이전에 플레이어임!
return 0;
}
Move Player !
Move Knight !
Move Player !
Knight k;
MovePlayer(&k);
Knight
객체를 넣어주었음에도 Player::Move()
메소드가 실행되었다는 것을 알 수 있음.Knight::Move()
메소드를 오버라이딩 해주었으니 상식적으로 Knight::Move()
가 실행되어야 하는 것이 아닌가?정적 바인딩은 일반적인 함수들은 거의 모두 해당된다고 생각하면 쉽다.
우리가 위의 코드에서 사용하거나 오버로딩, 오버라이딩 했던 함수들은 모두 정적 바인딩 된 것이다.
정적 바인딩은 '컴파일 시점'에서 결정된다.
즉, 위의 MovePlayer(Player* player)
메소드는 컴파일 시점(프로그램 실행 전)에 자신의 성격을 결정하였고, 매개변수로는 Player 객체가 들어올 것이라고 이미 결정한 것이다.
그러므로 매개변수로 Knight 객체가 들어왔다고 하더라도 Player::Move()
를 호출한 것이다.
하지만 이럴거면 우리는 굳이 오버라이딩을 할 이유가 없다.
열심히 만들어 둔 Knight::Move()
가 무용지물이 되지 않았는가?
하지만 이를 위해 c++에서는 virtual 키워드를 제공하고 있다.
이 키워드를 사용하면 '동적 바인딩'을 할 수 있게 되며, 해당 키워드를 사용한 함수는 '가상 함수'라고 칭한다.
동적 바인딩을 하게 되면 함수의 성격은 런타임에 결정되며, 매개변수로 들어온 객체에 따라 Player::Move()
또는 Knight::Move()
를 호출할 수 있게 된다.
class Player
{
public:
// 가상함수 <- 동적 바인딩을 써보자
virtual void VMove() { cout << "Move Player !" << endl; }
};
class Knight : public Player
{
public:
// 가상 함수는 재정의를 하더라도 가상 함수다!
// virtual 키워드를 제거해도 여전히 가상 함수임.
// virtual void VMove() == void VMove()
virtual void VMove() { cout << "Move Knight !" << endl; }
};
void VMovePlayer(Player* player)
{
// 동적 바인딩 -> 런타임에 결정 -> virtual 키워드
// 매개변수에 들어오는 객체 종류에 따라 Player::VMove() 또는 Knight::VMove() 가 실행될 수도 있음.
player->VMove();
}
int main()
{
Knight k;
VMovePlayer(&k);
Player p;
VMovePlayer(&p);
return 0;
}
Move Knight !
Move Player !