using System.ComponentModel;
using System.Numerics;
using System.Threading;
namespace CSharp
{
// 다형성
// 클래스 형식 변환
//
class Player
{
protected int hp;
protected int attack;
// 플레이어가 이동하는 방식이 기사가 이동하는 방식과 메이지가 이동하는 방식이 같다고 할 수 없음
// 따라서 각각의 함수 정의
public virtual void Move()
{
Console.WriteLine("Player 이동!");
}
}
class Knight : Player
{
// 새로운 기능을 추가하겠다는 키워드 new
// 오버라이딩을 사용하기 위해서는 virtual override가 필수 만약에 virtual 키워드를 안사용 하고 override를 사용한다면 컴파일 단계에서 오류를 내줌
public sealed override void Move() // sealed 나까지는 상속 받아서 오버라이드 하지만 그 다음 부터는 안됨
{
// 부모의 함수를 호출하고 사용할 수 있음
base.Move();
Console.WriteLine("Knight 이동!");
}
}
class SuperKnight :Knight
{
public override void Move() { Console.WriteLine("SuperKnight 이동"); } // sealed를 사용하면 사용 불가 컴파일 에러
class Mage : Player
{
public int mp;
public override void Move()
{
Console.WriteLine("Mage 이동!");
}
}
internal class Program
{
static void EnterGame(Player player)
{
player.Move();
// 기본적인 방법
// 타입을 체크하는 문법이 있어야 정상
// 체크하는 문법은\
// is키워드
//bool isMage = (player is Mage);
//if (isMage)
//{
// //Mage mage = (Mage)player;
// //
//}
// as키워드
Mage mage = (player as Mage);
if (mage != null)
{
mage.mp = 10;
mage.Move();
}
Knight knight = (player as Knight);
if (knight != null)
{
knight.Move();
}
}
static void Main(string[] args)
{
// 스택에서는 메모리 주소를 참조하고 -> 실제 데이터는 힙메모리에 생김
Knight knight = new Knight();
Mage mage = new Mage();
knight.Move();
mage.Move();
EnterGame(knight);
}
}
}
// 오버로딩 : 함수이름의 재사용
// 오버라이딩 : 함수 재정의 // 런타입에 체크하여 맞는 함수 호출
다형성(Polymorphism)은 부모 클래스를 기반으로 자식 클래스들이 서로 다른 방식으로 동작할 수 있도록 하는 객체 지향 프로그래밍(OOP)의 핵심 개념입니다. 이를 통해 코드의 재사용성과 유지보수성을 높일 수 있습니다.
virtual과 override: 가상 메서드(virtual method)를 이용해 다형성을 구현할 수 있음.new 키워드: 부모 클래스와 동일한 이름의 메서드를 정의할 때 사용.virtual 키워드부모 클래스의 메서드를 자식 클래스에서 재정의하여 다형성을 구현하는 방법.
class Player
{
public int hp;
public int attack;
public virtual void Move()
{
Console.WriteLine("Player Move");
}
}
class Knight : Player
{
public override void Move()
{
Console.WriteLine("Knight Move");
}
}
class Mage : Player
{
public override void Move()
{
Console.WriteLine("Mage Move");
}
}
class Program
{
static void Test(Player player)
{
player.Move(); // 각 자식 클래스에서 재정의한 Move()가 실행됨
}
static void Main()
{
Player player1 = new Knight();
Player player2 = new Mage();
Test(player1); // "Knight Move"
Test(player2); // "Mage Move"
}
}
Move() 메서드에 virtual을 붙여야 함.override를 사용하여 메서드를 재정의함.Player 타입으로 다룰 수 있으며, 재정의된 메서드가 호출됨.new 키워드와 다형성부모 클래스와 동일한 이름의 새로운 메서드를 정의할 때 사용.
new 키워드)class Player
{
public void Move()
{
Console.WriteLine("Player Move");
}
}
class Knight : Player
{
public new void Move()
{
Console.WriteLine("Knight Move");
}
}
class Program
{
static void Main()
{
Knight knight = new Knight();
knight.Move(); // "Knight Move"
Player player = new Knight();
player.Move(); // "Player Move" (업캐스팅 시 부모 클래스의 메서드 호출)
}
}
new 키워드 특징new 키워드를 생략해도 동일하게 동작하지만, 명시적으로 선언하는 것이 좋음.자식 객체를 부모 타입으로 변환하는 것.
Player player = new Knight(); // ✅ 자동 형변환 (업캐스팅)
player.Move(); // "Knight Move" (다형성 적용 시)
부모 타입 변수를 다시 자식 타입으로 변환하는 것.
Player player = new Knight();
Knight knight = (Knight)player; // ✅ 명시적 형변환 필요
knight.Move(); // "Knight Move"
❌ 잘못된 다운캐스팅 (런타임 오류 발생)
Player player = new Knight();
Mage mage = (Mage)player; // ❌ 런타임 오류 발생!
player는 Knight 객체를 참조하고 있으므로 Mage로 변환 불가능.InvalidCastException 예외 발생.is, as 키워드)is 연산자 사용Player player = new Knight();
if (player is Knight)
{
Knight knight = (Knight)player;
knight.Move();
}
as 연산자 사용Player player = new Mage();
Mage mage = player as Mage;
if (mage != null)
{
mage.Move();
}
sealed 키워드 (오버라이딩 제한)특정 메서드가 더 이상 오버라이딩되지 않도록 제한.
class Player
{
public virtual void Move()
{
Console.WriteLine("Player Move");
}
}
class Knight : Player
{
public sealed override void Move()
{
Console.WriteLine("Knight Move");
}
}
class SuperKnight : Knight
{
// public override void Move() ❌ 컴파일 에러 (sealed 때문에 재정의 불가능)
}
sealed 키워드 특징