프로그램을 실행을 할 때 실제 메모리에 저장된 타입을 기준으로 어떤 함수를 호출할지 결정됨
Entity* eptr = new Boss{ 0,0,2};
eptr -> Move(1,1); // Boss :: Move()
실제 메모리에 Boss가 올라가 있고 eptr이 Boss를 가리키고 있기 때문에 Boss의 Move()가 실행된다.
Move()와 같이, 유도 클래스에서 기본 클래스의 함수를 재정의 또는 오버라이드해 사용할 수 있음
오버라이드된 함수는 동적 바인딩을 통해 12,13 페이지의 예제와 같이 활용 가능
오버라이드 될 수 있는 함수를 가상 함수라 함
CPP에서 런타임 다형성(동적 바인딩)의 구현을 위해 아래와 같은 조건이 필요( 중요함 )
- 상속
- 기본 클래스 포인터 또는 참조자
- 가상 함수
선언 방법
오버라이드 할 함수를 기본 클래스에서 virtual로 선언 해주어야 함
상속 계층구조에 있는 모든 해당 함수는 가상 함수가 됨
class Entity{
Public:
virtual void Move( int dx, int dy);
-----
};
기본 클래스의 멤버 함수 앞에 virtual 키워드를 붙이면, 가상 함수가 됨
#include <iostream>
class Entity
{
protected:
int x, y;
public:
Entity(int x, int y)
:x{ x }, y{ y } {}
void Move(int dx, int dy)
{
x += dx;
y += dy;
}
void PrintPosition()
{
std::cout << x << "," << y << std::endl;
}
};
class Player : public Entity
{
private:
int hp;
int xp;
public:
Player(int x, int y ,int hp , int xp)
:Entity{x,y},hp{hp},xp{xp}{}
void Move(int dx, int dy)
{
x += dx * 2;
y += dy * 2;
}
};
int main()
{
Player e{ 1,1,10,10 };
e.PrintPosition();
e.Move(2,1);
e.PrintPosition();
return 0;
}
#include <iostream>
class Entity
{
protected:
int x, y;
public:
Entity(int x, int y)
:x{ x }, y{ y } {}
virtual void Move(int dx, int dy)//가상 함수 ,유도 클래스에서 오버라이딩 가능
{
x += dx;
y += dy;
}
void PrintPosition()
{
std::cout << x << "," << y << std::endl;
}
};
class Player : public Entity
{
private:
int hp;
int xp;
public:
Player(int x, int y ,int hp , int xp)
:Entity{x,y},hp{hp},xp{xp}{}
virtual void Move(int dx, int dy)
//여기서는 virtual 사용 할 필요없지만 협업을 위한 명시적 표현이다.
{
x += dx * 2;
y += dy * 2;
}
};
int main()
{
Player e{ 1,1,10,10 };
e.PrintPosition();
e.Move(2,1);
e.PrintPosition();
return 0;
}
위의 코드와 같이 virtual 선언을 해주어 유도 클래스에서 오버라이딩이 가능하게 만들어 준다.
overriding을 하기 위해서는 함수명, 함수 반환형, 매개변수가 같아야 오버라디잉이 가능하다.
유도 클래스의 오버라이딩한 함수도 virtual을 사용하여 명시적으로 표현을 해주어 협업자가 굳이 다른 코드를 찾아보지 않아도 파악이 가능하게 해준다.
오버라이드 할 함수를 유도 클래스에서 구현
함수 원형과 반환형이 기본 클래스의 가상 함수와 일치해야 함!
유도 클래스의 함수에서는 virtual 키워드를 넣지 않아도 되지만, 혼동을 피하기 위해 명시해 주는 것을 권고
유도 클래스에서 함수를 오버라이드 하지 않으면, 기존과 같이 기본 클래스의 함수가 상속됨
class Player : public Entity
{
public:
virtual void Move(int dx, int dy);
-----
}
유도 객체를 올바른 순서로, 올바른 소멸자를 사용해 소멸시키는 방법이 필요
해결 방법 ? → 가상 소멸자
#include <iostream>
class Entity
{
protected:
int x, y;
public:
Entity(int x, int y)
:x{ x }, y{ y } {}
~Entity()
{
std::cout << "Entity 소멸자 호출됨" << std::endl;
}
virtual void Move(int dx, int dy)//가상 함수 ,유도 클래스에서 오버라이딩 가능
{
x += dx;
y += dy;
}
void PrintPosition()
{
std::cout << x << "," << y << std::endl;
}
};
class Player : public Entity
{
private:
int hp;
int xp;
public:
Player(int x, int y ,int hp , int xp)
:Entity{x,y},hp{hp},xp{xp}{}
~Player()
{
std::cout << "Player 소멸자 호출됨" << std::endl;
}
virtual void Move(int dx, int dy)
{
x += dx * 2;
y += dy * 2;
}
};
int main()
{
Entity* e = new Player{ 1,1,10,10 };
delete e;
return 0;
}
코드를 실행 시키면 우리는 Player의 소멸자는 호출되지 않고 Entity의 소멸자만 호출이 되는 것을 볼 수 있다. 우리는 Player 객체를 생성을 했기 때문에 Player 소멸자가 호출이 되어야만 한다.
#include <iostream>
class Entity
{
protected:
int x, y;
public:
Entity(int x, int y)
:x{ x }, y{ y } {}
virtual ~Entity()
{
std::cout << "Entity 소멸자 호출됨" << std::endl;
}
virtual void Move(int dx, int dy)//가상 함수 ,유도 클래스에서 오버라이딩 가능
{
x += dx;
y += dy;
}
void PrintPosition()
{
std::cout << x << "," << y << std::endl;
}
};
class Player : public Entity
{
private:
int hp;
int xp;
public:
Player(int x, int y ,int hp , int xp)
:Entity{x,y},hp{hp},xp{xp}{}
virtual ~Player()//명시적으로 보여줌
{
std::cout << "Player 소멸자 호출됨" << std::endl;
}
virtual void Move(int dx, int dy)//명시적으로 보여줌
{
x += dx * 2;
y += dy * 2;
}
};
int main()
{
Entity* e = new Player{ 1,1,10,10 };
delete e;
return 0;
}
간단하다. virtual을 ~Entity()에 붙여서 가상 소멸자로 만들어 주면된다.
-보면 헷갈릴수도 있는데 간단하게 생각해보면 내가 유도 클래스에서 정의한 동일한 이름의 함수는 ( 생성자, 소멸자 포함) 가상 함수로 선언을 하지 않으면 호출이 되지 않는다!