전체 코드

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);
        }

    }
}
// 오버로딩 : 함수이름의 재사용
// 오버라이딩 : 함수 재정의 // 런타입에 체크하여 맞는 함수 호출

1. 다형성이란?

다형성(Polymorphism)은 부모 클래스를 기반으로 자식 클래스들이 서로 다른 방식으로 동작할 수 있도록 하는 객체 지향 프로그래밍(OOP)의 핵심 개념입니다. 이를 통해 코드의 재사용성과 유지보수성을 높일 수 있습니다.

2. 다형성의 핵심 요소

  • 오버라이딩(Overriding): 부모 클래스의 메서드를 자식 클래스에서 재정의하여 다른 동작을 수행할 수 있도록 함.
  • 업캐스팅(Upcasting): 자식 객체를 부모 클래스 타입으로 변환하는 것.
  • 다운캐스팅(Downcasting): 부모 클래스 타입의 객체를 다시 자식 클래스 타입으로 변환하는 것.
  • virtualoverride: 가상 메서드(virtual method)를 이용해 다형성을 구현할 수 있음.
  • new 키워드: 부모 클래스와 동일한 이름의 메서드를 정의할 때 사용.

3. 오버라이딩과 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 타입으로 다룰 수 있으며, 재정의된 메서드가 호출됨.

4. 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 키워드 특징

  • 오버라이딩과 달리 부모의 메서드를 완전히 숨김 (Hiding).
  • 업캐스팅하면 부모 클래스의 메서드가 호출됨.
  • new 키워드를 생략해도 동일하게 동작하지만, 명시적으로 선언하는 것이 좋음.

5. 업캐스팅과 다운캐스팅

🔹 업캐스팅 (Upcasting)

자식 객체를 부모 타입으로 변환하는 것.

Player player = new Knight(); // ✅ 자동 형변환 (업캐스팅)
player.Move(); // "Knight Move" (다형성 적용 시)

🔹 다운캐스팅 (Downcasting)

부모 타입 변수를 다시 자식 타입으로 변환하는 것.

Player player = new Knight();
Knight knight = (Knight)player; // ✅ 명시적 형변환 필요
knight.Move(); // "Knight Move"

잘못된 다운캐스팅 (런타임 오류 발생)

Player player = new Knight();
Mage mage = (Mage)player; // ❌ 런타임 오류 발생!
  • playerKnight 객체를 참조하고 있으므로 Mage로 변환 불가능.
  • InvalidCastException 예외 발생.

6. 안전한 다운캐스팅 (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();
}

7. 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 키워드 특징

  • 자식 클래스에서 더 이상 오버라이딩할 수 없도록 보호함.
  • 불필요한 메서드 재정의를 방지하여 코드의 안정성을 높임.

profile
李家네_공부방

0개의 댓글