Chapter 5-4. 객체 지향 : 클래스 형변환(is, as)
카테고리: C Sharp
태그: C Sharp Programming
인프런에 있는 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(); // ❌ 컴파일 에러!
- 자식(Knight)타입의 객체(
- 다운 캐스팅 : 부모 👉 자식 (경우에 따라 다름)
- 묵시적 형변환을 해주지 않는다. (컴파일 에러)
- 자식타입의 객체(
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
가 어떤 객체를 가리키고 있는지 알 수 없고 런타임 때 해당 코드를 실행해 봐야 알 수 있는 부분인데,Knight
과Maze
는 둘 다Player
자식이긴 하지만Knight
타입의 객체는Maze
에만 정의되어 있는Maze
의 멤버들을 담고 있지 않기 때문이다. 따라서Maze
타입의 변수mage
로Knight
타입의 객체를 참조할 수 없기 때문에,Knight
타입의 객체를 가리키고 있는player
는Mage
로 형변환 될 수 없다.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;
player
는 Knight
타입의 객체를 참조하고 있기 때문에 (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;
player
는 Mage
타입의 객체를 참조하고 있기 때문에 Mage
로 형변환이 가능하다. 따라서 mage
엔 player
가 참조하고 있던 객체가 리턴되고 mage
와 player
는 힙메모리에 있는 동일한 객체를 가리키게 된다. mage
는 player
가 Mage
로 형변환된 결과다. 따라서 Mage mage = (Mage)player;
이 부분이 실행된다. 형변환이 불가능 했다면 이 부분은 실행되지 않았을 것이다. 안전함.
🌜 개인 공부 기록용 블로그입니다. 오류나 틀린 부분이 있을 경우
언제든지 댓글 혹은 메일로 지적해주시면 감사하겠습니다! 😄
댓글 남기기