앞선 [C#] Casting에서 언급한 내용에서 추가적으로 클래스 간의 형변환도 가능합니다.
사진처럼 자식 객체에서 부모 객체로 형변환하는 것을 업캐스팅이라고 합니다. 자식 타입의 객체를 부모 타입의 변수로 참조하는 것입니다.
단, 자식 타입의 객체의 전부에 접근할 순 없고 부모로부터 상속받은 멤버들만 접근이 가능합니다. 자식만의 멤버에 접근하려 하면 컴파일 오류가 발생합니다.
반대로 부모 객체에서 자식 객체로 형변환하는 것을 다운캐스팅이라고 합니다. 다운캐스팅은 묵시적 형병환을 해주지는 않습니다. 컴파일 오류가 발생하죠.
자식 타입의 객체를 참조하던 부모 타입 변수를 자식 타입으로 형변환해주는 것은 가능합니다. 하지만 컴파일러는 자동으로 해주지는 않습니다. 컴파일러 타임에는 부모 타입 변수가 어떤 타입의 객체를 가리키고 있는지 알 수가 없기 때문입니다. 객체가 메모리를 할당받는 일은 런타임이기 때문에 컴파일 타임에선 부모 타입의 변수가 어떤 타입의 객체를 가리키고 있는지 알 수 없어 자동적으로 형병환을 해주지 않습니다. 따라서, 명시적 형변환을 해주어야 합니다.
명시적 형변환에서도 문제가 없진 않습니다. 컴파일에선 문제가 없지만 런타임 시에 오류가 발생할 수 있습니다. 부모 타입의 변수가 자식 타입으로 명시적 형변환을 할 땐 문제가 없지만 같은 부모를 가진 다른 자식 타입으로 명시적 형변환을 할 때에는 런타임 오류가 발생합니다. 자식 타입끼리는 서로가 공유하지 않는 멤버들이 존재할 수도 있기 때문입니다.
이를 방지하기 위한 2가지 방법이 있습니다. 바로 is, as 입니다.
A is B 👉 A 변수가 B 타입의 객체를 참조하고 있다면 True, 아니면 False를 반환합니다.
Weapon weapon = new Knife();
bool isKnife = (weapon is Gun);
if (isKnife)
{
Knife knife = (Knife)weapon;
}
weapon은 Knife 타입의 객체를 참조하고 있기 때문에 weapon is Gun의 결과는 False입니다. 따라서, Knife knife = (Knife)weapon이 실행되지 않기 때문에 런타임 오류를 방지할 수 있습니다.
A as B 👉 A 변수를 B 타입으로 형변환하는 것이 가능하다면 형변환을 진행하고 그 결과를 반환합니다. 불가능하다면 null을 반환합니다.
Weapon weapon = new Gun();
Gun gun = (weapon as Gun);
if (gun != null)
{
Gun gun = (Gun)weapon;
}
weapon은 Gun 타입의 객체를 참조하고 있기 때문에 Gun 타입으로 형변환이 가능합니다. 따라서, gun에는 weapon이 참조하고 있던 객체라 반환되고 gun과 weapon은 힙에 있는 동일한 객체를 가리키게 됩니다. gun은 weapon이 Gun 타입으로 형변환된 결과입니다.