🚗 new (다형성 X)
부모 클래스로부터 상속 받은 함수와 이름은 동일하지만 이와 상관없는 완전히 새로운 함수로서 재정의하고 싶다면 new 키워드를 사용하면 된다! Player의 Move()와 Knight의 Move()는 완전히 다른 함수다. (new를 꼭 붙이지 않아도 됨.)
🚕 다형성 (가상함수 virtual, 오버라이딩 override)
매개변수인 player는 인수로 꼭 Player 타입의 객체 뿐만 아니라 그의 자식들인 Knight, Maze 타입의 객체도 참조할 수 있다. player에 어떤 타입의 객체가 들어오느냐에 따라서 player.Move()의 출력값이 다르게 실행될 수 있다! Player에서 Move()를 가상함수로 선언하고, 자식 클래스에서 이 가상함수를 오버라이딩(재정의) 하면 된다. 이를 다형성이라고 한다!
- player.Move();
- Player player = new Player();
- Player의 Move() 실행. “Player Move” 출력
- Player player = new Knight();
- Knight의 Move() 실행. “Knight Move” 출력
- Player player = new Mage();
- Mage의 Move() 실행. “Mage Move” 출력
부모 클래스에서 가상 함수는 virtual 키워드를 붙이면 되고, 자식 클래스에서 이 가상 함수를 오버라이딩 하려면 override 키워드를 붙이며 된다. virtual은 성능 부하가 있기 때문에 남발하여 만들지 않고 꼭 다형성이 필요한 경우만 가상 함수로 선언하는 것이 좋다. 재정의 없이 그대로 상속 받는 경우가 많은게 성능상 좋긴 하다!
Player의 Move()는 가상 함수이나 자식인 Knight 클래스에선 이를 오버라이딩 하지 않았다. 따라서 부모의 Move()와는 관련 없이 이름만 똑같을 뿐인 새로운 Move()를 정의하는 것과 같다. 즉, new를 붙인 것과 같은 상태다. 따라서 업캐스팅 하였어도 player.Move()는 Player의 Move()가 호출된다. (C++, C#은 Java와 달리 참조 하는 '변수'의 타입을 기준으로 멤버 함수를 호출한다. 가상 함수여서 다형성을 실행하는게 아니라면 변수의 타입을 기준으로 호출한다.)
🚓 sealed
sealed는 오버라이딩 할 때 같이 사용된다. 손자, 증손자 클래스들에서 더이상 오버라이딩 하지 못하게, 딱 나까지만 오버라이딩이 가능하도록 강제한다! C++에선 없고 C#에서만 있는 문법이며 그리 자주 쓰이진 않는다.
Knight에서 Move()를 오버라이딩할 때 sealed 키워드를 통해 봉인해 두었기 때문에 손자 클래스인 SuperKnight에선 Move()를 오버라이딩 할 수 없다. 상속 받은 것을 그대로 써야 한다.