SW Programming/C#

[C#] 상속과 다형성

victoryAshe 2022. 6. 1. 08:27

상속

다른 클래스의 멤버를 이어받는 기능으로, 기본 클래스와 파생클래스가 1:N의 관계를 갖는다.

  • 파생클래스의 객체는 기본 클래스의 private을 제외한 멤버를 사용할 수 있다.
  • 기본 클래스(부모 클래스): 상속하는 바탕이 되는 클래스
  • 파생 클래스(자식 클래스): 상속하여 만든 클래스
  • sealed: 다른 클래스에서 상속 불가능하도록 하는 키워드. virtual메서드를 override한 메소드에도 지정 가능
  • base : 상속 원본에 인수를 전달하는 키워드 -> 기본 클래스의 인수가 있는 생성자를 호출
    • base 사용하지 않으면: 상속 원본의 인수가 없는 생성자 호출
    • 이름의 은폐가 일어날 때, 은폐된 기본 클래스 멤버를 파생 클래스 안에서 사용할 때에도 이용
      -> base.a: 기본클래스 필드의 a
 using System;

class Calc1{
    public int x;
    public Calc1(int a, int b) { x = a+b;}
}

class Calc2 : Calc1 {
    public Calc2(int c, int d) : base(c, d) {}
}

class Calc3 {
    public static void Main(){
        Calc2 calc2 = new Calc2(1, 2);
        Console.WriteLone(calc2.x);   // 결과: 3
    }
}

다중상속을 허용하는 C++과는 다르게, C#은 단일상속을 원칙으로 한다.

  • 단, 구현을 생략한 선언만 물려주는 인터페이스는 다중상속을 허용한다.
  • C++에서는 '가상상속'이라는 개념을 사용해 다중상속을 계속 이끌어나간다.
  • 죽음의 다이아몬드 문제: 하나의 부모 클래스를 두 개의 자식 클래스가 상속받고, 이 두개의 자식 클래스를 다시 하나의 자식 클래스가 상속하는 예시.
    the Deadly Diamond of Death_ex
    이 때, 마지막 상속 개체가 사용할 Bark()메서드가 어느 쪽의 것인지 모호해지는 모호성이 죽음의 다이아몬드 문제의 핵심이다. 프로그래밍 언어는 같은 구문이 두 가지 이상의 의미로 해석되지 않아야 하기 때문이다. 다중 상속은 이러한 문제를 야기할 수 있으므로 C#에서는 다중상속을 허용하지 않는다.
    • 파생 클래스는 기본 클래스의 virtual 멤버를 override하여 사용할 수 있으며(선택), abstract 멤버는 override해야 한다(필수).

다형성

한 객체나 메소드가 다양한 형태를 가지는 것

  • 파생 클래스 객체: 기본 클래스의 객체로 취급할 수도, 파생 클래스 객체로 취급할 수도 있다.
  • 이 때, 형 변환은 자식type의 참조변수 -> 부모type의 참조변수, 또는 그 반대의 형변환만 가능하다.
    📌 단, 다운 캐스팅은 업 캐스팅을 시행한 변수에서만 시행 가능. 다른 경우에 사용시 InvalidCastException 예외 발생
    • 업 캐스팅: 자식type의 참조변수를 부모type의 참조변수로 변환 (형변환 생략 가능)
    • 다운 캐스팅: 부모type의 참조변수를 자식type의 참조변수로 변환(형변환 생략 불가)

🌟 upcasting했을 때는 child 객체의 필드를 사용할 수 없다.
: 이 때, child에서 override한 메소드가 있다면 parent의 것이 아닌 child의 것을 사용

반대로, upcasting한 것을 다시 downcasting을 했을 때는 child의 필드를 다시 사용 가능
: 이 때, 상속을 받았으므로 parent의 필드도 사용 가능

class A{
    public int m;
    public virtual void p(){}
}

class B: A {
    public int n;
    public override void p(){}
}

class Program{
    static void Main(){
        A a = new B();  // 업 캐스팅
  B b = null;
  b = (b)a;       // 다운 캐스팅
    }
}
  • as연산자와 is연산자를 이용한 형변환
    오류를 발생시키지 않고 형변환이 가능한지 확인할 수 있는 방법!
    • as: 형변환이 가능하면 지정된 타입의 인스턴스를 반환, 가능하지 않으면 null 반환
      -> null 반환 여부를 통해 형변환이 성공했는지 알 수 있다!
    • is: 형변환의 가능 여부를 bool 타입의 결과값으로 반환.
      -> 참조 형식 뿐 아니라 값 형식에도 사용 가능
    • 인터페이스를 이용한 다형성
      • 인터페이스는 그것을 구현한 클래스의 부모라고 할 수 있다.
        -> 해당 인터페이스 타입의 참조변수로 이를 구현한 클래스의 인스턴스를 참조할 수 있다.
interface ILogger // 인터페이스
{
   void WriteLog(string log);
}

class ConsoleLogger : ILogger // 인터페이스를 구현한 클래스
{
  public void WriteLog(string log)
  {
     Console.WriteLine("{0} {1}", DateTime.Now.ToLocalTime(), log);
  }
}

class Program
{
  static void Main()
  {
     ILogger logger = new ConsoleLogger();  // 인터페이스를 이용한 다형성
  }
}

출처

  1. 괭이쟁이
  2. bamsunbic의 기술 블로그
  3. C#이 보이는 그림책, 성안당
  4. 이것저것 개발 블로그
  5. 나의 지식 보관소