Chapter 5-4. 객체 지향 : 클래스 형변환(is, as)

Date:     Updated:

카테고리:

태그:

인프런에 있는 Rookiss님의 강의 Part1: C# 기초 프로그래밍 입문 를 듣고 정리한 필기입니다. 😀

👱‍♀️ 클래스 형식 변환

부모 자식간 형식 변환

Knight knight = new Knight();

knight 스택 메모리에서 new Knight()로 생성한 힙 메모리 객체의 주소를 담는다.

부모 👉 Plyaer
자식 👉 Knight, Maze
    class Player
    {
        public int hp;
        public int attack;
    }
    class Knight : Player
    {
        public void Move() { Console.Write("Kight Move"); }
        public void Attack() { Console.Write("Kight Attack"); }
    }

    class Mage : Player
    {
        public void Move() { Console.Write("Maze Move"); }
        public void Attack() { Console.Write("Maze Attack"); }
    }
  • 업 캐스팅 : 자식 👉 부모
    • 자식(Knight)타입의 객체(new Knight();)를 부모 타입의 변수(player)로 참조하는 것 가능하다.
    • 단 자식 타입의 전부를 호출할 순 없고, 부모로부터 상속 받은 멤버들만 호출이 가능하다. 자식 객체를 참조하고 있더라도 부모 변수로 상속 받지 않은 자식만의 멤버를 호출하려 하면 컴파일 에러를 발생시킨다.
      Knight knight = new Knight();
      Player player = knight; // ⭕ 문제없다.
      
      player.hp = 10; // ⭕ 문제없다.
      player.Move();  // ❌ 컴파일 에러!
      
  • 다운 캐스팅 : 부모 👉 자식 (경우에 따라 다름)
    • 묵시적 형변환을 해주지 않는다. (컴파일 에러)
      • 자식타입의 객체(new Knight();)를 참조하던 부모 타입 변수(player)를 다시 자식 타입으로 형변환 해주는 것이 가능하다. 그러나 컴파일러는 이를 자동 형변환 해주지 않는다. 컴파일러 타임엔 부모 타입 변수인 player가 어떤 타입의 객체를 가리키고 있는지 알 수 없기 때문이다. 객체가 메모리를 할당 받는 일은 해당 코드가 실행되는 런타임이기 때문에 컴파일 타임에선 player가 어떤 타입의 객체를 가리키고 있는지 알 수 없서 자동적으로 형변환을 해주지 않는다. 따라서 개발자가 직접 명시적으로 형변환을 해주어야 한다.
        Player player = new Knight();
        Knight knight = player;  // ❌ 컴파일 에러! 자동 형변환 해주지 않음.
        Knight knight = (Knight)player;  // ⭕ 이렇게 명시적 형변환을 해주어야 한다. 
        
    • 명시적 형변환은 컴파일에선 문제 없으나 경우에 따라 런타임 에러가 발생할 수도 있다.
      • 실제로 형변환이 가능한지는 프로그램을 실행해 봐야 알 수 있다. 객체가 메모리를 할당 받는 일은 해당 코드가 실행되는 런타임이기 때문이다.
      • ⭕ 아래의 경우엔 런타임 에러가 발생하지 않는다. 문제 없다.
        • 다시 원래 타입의 객체로 돌려주는 일이기 때문이다. 부모 타입 변수 player는 자식 타입인 Knight 타입 객체를 참조하고 있었기 때문에 player 변수를 Knight 타입으로 형변환 해주는 것이 문제 되지 않는다. 안그래도 Knight 타입 객체를 참조있었기 때문에!
          Player player = new Knight();
          Knight knight = (Knight)player;  // ⭕ 문제 없다.
          
      • ❌ 아래의 경우엔 런타임 에러가 발생한다.
        • 부모 타입 변수 player는 자식 타입인 Knight 타입 객체를 참조하고 있었기 때문에 Maze타입으로 형변환 될 수 없다. 이게 컴파일 타임에선 player가 어떤 객체를 가리키고 있는지 알 수 없고 런타임 때 해당 코드를 실행해 봐야 알 수 있는 부분인데, KnightMaze는 둘 다 Player 자식이긴 하지만 Knight타입의 객체는 Maze에만 정의되어 있는 Maze의 멤버들을 담고 있지 않기 때문이다. 따라서 Maze 타입의 변수 mageKnight타입의 객체를 참조할 수 없기 때문에, Knight타입의 객체를 가리키고 있는 playerMage로 형변환 될 수 없다.
          Player player = new Knight();
          Mage mage = (Mage)player;  // ❌ 런타임 에러 발생!
          
          Unhandled Exception: System.InvalidCastException: Unable to cast object of type 'CSharp.Knight' to type 'CSharp.Mage'.
          


다운 캐스팅시 런타임 에러 방지 문법

is

A is B 👉 A 변수가 B 타입의 객체를 참조하고 있다면 True 리턴, 아니면 False 리턴.

Player player = new Knight();

bool isMage = (player is Mage)
if (isMage)
    Mage mage = (Mage)player;

playerKnight 타입의 객체를 참조하고 있기 때문에 (player is Mage)의 결과는 False 이다. 따라서 Mage mage = (Mage)player; 이 부분이 실행되지 않기 때문에 런타임 에러를 방지할 수 있다.


as

A as B 👉 A 변수를 B 타입으로 형변환 하는 것이 가능하다면 형변환을 진행하고 그 결과를 리턴한다. 불가능하다면 null을 리턴한다.

Player player = new Mage();

Mage mage = (player as Mage)
if (mage != null)
    Mage mage = (Mage)player;

playerMage 타입의 객체를 참조하고 있기 때문에 Mage로 형변환이 가능하다. 따라서 mageplayer가 참조하고 있던 객체가 리턴되고 mageplayer는 힙메모리에 있는 동일한 객체를 가리키게 된다. mageplayerMage로 형변환된 결과다. 따라서 Mage mage = (Mage)player; 이 부분이 실행된다. 형변환이 불가능 했다면 이 부분은 실행되지 않았을 것이다. 안전함.



🌜 개인 공부 기록용 블로그입니다. 오류나 틀린 부분이 있을 경우 
언제든지 댓글 혹은 메일로 지적해주시면 감사하겠습니다! 😄

맨 위로 이동하기

C Sharp 카테고리 내 다른 글 보러가기

댓글 남기기