Language/C#

C# 공부정리 - 클래스 3 (상속, base, is, as)

Tarel 2023. 1. 3. 19:44

클래스에서 가장 중요한 부분중 하나인 상속에 대해서 알아보자

 

상속

클래스에는 부모자식 관계라는 것이 있다.

부모클래스를 base, parent, 상위, super 등으로 부르고

자식클래스를 derived, child, 파생, sub 등으로 부른다.

 

예를들어, 옷 이라는 개념을 보자

옷에는 봄옷, 여름옷, 가을옷, 겨울옷 이라는 하위 개념이 있고

그 중 겨울옷에는 패딩, 코트, 목도리와 같은 하위 개념이 있으며

패딩에는 롱패딩, 숏패딩이라는 하위개념이 있다.

 

여기서 옷이 부모클래스라면 겨울옷은 자식클래스이며

겨울옷이 부모클래스라면 패딩이나 코트가 자식클래스가 되는 것이다.

 

즉, 상위 개념과 하위 개념이라고 생각할 수 있다.

 

그렇다면 상속은 어디에 사용할까?

 

게임에는 몬스터가 있고 몬스터 종류로 스켈레톤과 슬라임이 있다고 가정해보자

같은 몬스터인 스켈레톤과 슬라임은 분명 공유하는 무언가가 있을 것인데

이 공유하는 무언가를 몬스터라는 상위 개념에서 상속받아서 사용한다.

 

아래 예시를 보자

class Super
{
    protected int a;			// 새로운 접근 지정자
    public void Print() {
        Console.WriteLine("Super Print()");
    }
}

class Sub:Super
{
    int b;
    public void Print() {
        Console.WriteLine( a, b);
    }
}

시작하기 전에 Super 클래스의 protected int a; 가 있는데

여기서 protected라는 접근 지정자는 본인 클래스와 본인 클래스의 상속을 받은 클래스만 접근할 수 있다는 뜻이다.

참고로 int a의 접근지정자가 public이어도 sub클래스에서 사용할 수 있지만 private 일 경우는 불가능 하다.

 

Super 라는 클래스가 부모 클래스이고 아래 Sub라는 클래스가 자식 클래스다.

Sub는 Super의 상속을 받는다.

때문에 Sub클래스의 Print를 작동하면 Super의 a를 가져와서 사용한다.

 

상속 - 생성자와 소멸자

class Super
{
    public Super() {
        Console.WriteLine("Super 생성");
    }
    ~Super() {
        Console.WriteLine("Super 소멸");
    }
}
class Sub:Super
{
    public Sub() {
        Console.WriteLine("Sub 생성");
    }
    ~Sub() {
        Console.WriteLine("Sub 소멸");
    }
}

class Program
{
    static void Main(string[] args) {
        Sub sub = new Sub();
    }
}

위 코드를 요약하면 부모와 자식 클래스에서 생성자와 소멸자를 호출하고

Main 함수에서는 자식클래스만 불러오는 것이다.

 

출력 결과는 부모 생성자 -> 자식 생성자 -> 자식 소멸자 -> 부모 소멸자 순서대로 진행된다.

그런데 만약 Main 함수에서 Sub sub = new Sub();로 자식 클래스를 사용하는 것이 아닌

Super super = new Super();로 부모클래스를 부른다면 출력결과가

 

부모 생성자 -> 부모 소멸자 로 자식 클래스는 완전히 빠지게 된다.

 

base

base키워드는 부모의 생성자 함수를 불러오는데 사용한다.

this와도 유사한 부분이 보이는데 이는 후술한다.

위 코드에서, 자식 클래스인 Sub에서 Sub 생성자가 두 개의 파라미터를 받는데

그 중 num에 해당하는 것을 부모 클래스의 Super의 파라미터(int num)에 대입하겠다는 것을 뜻한다.

 

또, Sub 클래스에서 PrintSub() 함수를 보면

base.name 이 있는데 이는 부모 클래스에 있는 name을 뜻한다.

 

어찌보면 this 하고 비슷한데, this 가 클래스 본인 자체를 말하는 거라면

base는 자신을 상속해준 부모클래스를 뜻하는 키워드라고 볼 수 있다.

 

is

is는 객체의 형식을 검사한다.

bool을 리턴한다는 특징이 있다.

먼저 Base 클래스를 만들고 Base 클래스를 상속받는 AA 클래스와 BB 클래스를 만들었다.

 

Main 함수에선 AA 클래스를 가져오는데 Base에 넣었기 때문에 aa는 Base 클래스를 가져온 것이다.

이 때문에, 바로 아랫 줄에선 aa.PrintA() 가 아닌 aa.Print()가 사용된 것이다.

(이부분 헷갈릴 수 있으므로 주의)

 

자, Base에 AA를 담에서 aa를 선언했다.

그렇다면 aa는 AA가 되어야 할 것이니 바로 아래 조건문에서는 

aa is AA가 true가 된다.

 

 

as

as는 일종의 강제 형 변환이라고 볼 수 있다.

null을 리턴한다는 특징이 있다.

위의 코드에서 Main 함수를 바꾼 것이다.

bb는 본래 Base에 담긴 BB였고 때문에 Base 클래스의 Print 함수에 접근할 수 있었다.

그러나 Base에서 BB로 형변환이 일어나면서 BB 클래스의 PrintB 함수에 접근할 수 있게 되었다.


사실 이 기능은 숙이 BB copyBB = bb as BB 가 아닌

BB copyBB = (BB)bb;를 사용할 수도 있다.

그러나 그러지 않는 이유는 예외발생으로 인한 애러를 방지하기 위해서 일부러 as를 사용한다.

 

사실 정확히 어떤 문제가 발생하는지는 잘 모르겠으나 잘못된 형변환을 할 경우 as 없이 사용하면

에러가 발생할 수 있다고 한다.

 

다형성