Chapter 9-2. 기타문법 : Interface(인터페이스) + 다중 상속이 가능한 이유

Date:     Updated:

카테고리:

태그:

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

👩🏼 추상 클래스

using System;
using System.Collections.Generic;

namespace CSharp
{
    abstract class Monster
    {
        public abstract void Shout(); 
    }

    class Orc : Monster
    {
        public override void Shout() { Console.WriteLine("오크~~"); }
    }

    class Skeleton : Monster
    {
        public override void Shout() { Console.WriteLine("빠각~~"); }
    }

    class SkeletonOrc : Orc, Skeleton // ❌❌ 컴파일 에러 ! 
    {

    }

    class Program
    {
        static void Main(string[] args)
        {
            Monster monster = new Monster(); // ❌❌ 컴파일 에러! 추상 클래스 타입의 객체는 만들 수 없다.

            Monster monster = new Orc(); // ⭕ 다형성
        }
    }
}

추상 클래스의 정의

    abstract class Monster
    {
        public abstract void Shout(); 
    }
  • 추상 클래스는 abstract 추상 함수를 가지고 있는 클래스를 뜻한다.
    • 추상 함수에도 abstract가 붙고, 추상 함수를 가지고 있다면 클래스 정의 앞에도 abstract를 붙여주어야 한다.
    • 추상 함수 말고도 가상 함수나 일반 멤버 함수나 멤버 변수를 가질 수 있다.
      • 어느 정도 구체적인 부분은 가질 수 있다는 얘기다. 👉 자식 클래스에게 물려주기 위해서
  • 추상 함수
    • 자식 클래스에서 반드시 오버라이딩 하도록 강제하는 함수다.
    • 가상 함수처럼 업 캐스팅시 자식이 오버라이딩한 함수를 호출하도록 한다. 👉 다형성
    • 가상 함수와는 달리 구현부{}를 작성하면 안된다. 함수의 인터페이스만 정의한다. 그래서 추상적으로 존재만 하는 함수라 추상 함수다!
      • 오로지 구현은 자식클래스에게 맡기며 이러이러한 기능을 꼭! 꼭! 재정의 해달라는 신호와도 같다.
      • 자식클래스에서 이를 오버라이딩 하지 않으면 컴파일 에러가 발생한다.

추상 클래스 주의할 점

1️⃣ 추상 클래스 타입의 객체 생성은 불가능하다.

Monster monster = new Monster(); // ❌❌ 컴파일 에러! 추상 클래스 타입의 객체는 만들 수 없다.
Monster monster = new Orc();  // ⭕ 다형성
  • 추상클래스인 Monster타입의 객체를 생성할 수는 없다. 👉 컴파일 에러
    • 추상 클래스엔 구현부가 없는 추상 함수가 있기 때문이다.
    • 추상 클래스가 존재하는 이유는 그 자체로 객체를 만들기 위함이 아니라, 자식 클래스에게 필요한 것들을 상속해주고, 특정 추상 함수를 꼭 구현하라고 강제하기 위함이다.
  • 다만 추상클래스 타입의 변수가 자식 클래스를 참조하는 업캐스팅은 가능하다. 👉 다형성


2️⃣ 다중 상속이 불가능하다 + 그 이유

C#에서는 추상 클래스와 그 외 평범한 일반 클래스들은 다중 상속이 불가능하다. 그 이유는 죽음의 다이아몬드 문제가 생길 수 있기 때문이다!

    abstract class Monster
    {
        public abstract void Shout(); 
    }

    class Orc : Monster
    {
        public override void Shout() { Console.WriteLine("오크~~"); }
    }

    class Skeleton : Monster
    {
        public override void Shout() { Console.WriteLine("물캉~~"); }
    }

    class SkeletonOrc : Orc, Skeleton  // ❌❌❌ 컴파일 에러 발생!
    {

    }
- 📜Monster
  - 📜Orc
  - 📜Skeleton
  • Orc 클래스와 Skeleton 클래스는 Monster 추상 클래스를 상속받는다.
    • 따라서 Orc 클래스와 Skeleton 클래스에서는 반드시 추상 함수 Shout()를 오버라이딩 해야 한다.
  • SkeletonOrc 클래스에서 Orc,Skeleton 를 둘 다 상속 받으려고 한다면 (다중 상속을 받는다고 가정해본다면)
    • SkeletonOrc 클래스에게 주어진 2 가지 선택지
      • 1️⃣ Shout()를 새롭게 오버라이딩 한다.
        • 문제 없다. 자신만의 내용으로서 새롭게 정의하는 것이기 때문에.
      • 2️⃣ 부모인 Orc,Skeleton 로부터 물려받은 Shout()를 오버라이딩하지 않고 물려받은 그대로 사용한다.
        • 👉 이 경우 문제 발생 !!
          • 부모인 Orc,Skeleton 둘 다 각자 오버라이딩 해서 구현부가 다른기 때문에 두 부모 클래스의 Shout()은 서로 다른 함수나 마찬가지다.
          • 따라서 SkeletonOrc 입장에선 어떤 Shout()을 상속 받아야 하는지 알 수 없다.
            • 죽음의 다이아몬드 문제 👉 그대로 상속 받아 쓰려고 할 때, 두 부모가 동일한 함수이나 오버라이딩으로 구현부가 다른 함수를 가지고 있기 때문에 오버라이딩 하지 않고 그대로 물려 받아 사용하려고 할 때 어떤 것을 사용해야할지 애매해지는 문제


👱‍♀️ 인터페이스

using System;
using System.Collections.Generic;

namespace CSharp
{
    interface IFlyable
    {
        void Fly();  // 접근 지정자 안붙임. abstract 이런것도 안붙임
    }

    class FlyableOrc : Orc, IFlyable
    {
        public void Fly()
        {

        }
    }

    class Program
    {
        static void DoFly(IFlyable flyable)
        {
            flyable.Fly(); // 아무 문제 없다.
        }
        static void Main(string[] args)
        {
            IFlyable flyable = new FlyableOrc();  // 다형성
        }
    }
}

인터페이스의 정의

추상함수’만’ 가지고 있는 클래스.

추상 클래스와 달리 다중 상속이 가능하다.

  • 앞에 interface 키워드를 붙여주며, class는 붙이지 않는다.
  • 추상 함수는 접근 한정자 같은 어떠한 키워드도 붙지 않는다. 기본적인 함수 프로토타입만 정의ㅣ.
  • 인터페이스 이름 앞엔 I를 붙여주는게 암묵적 약속이다.
  • 멤버 변수나 가상 함수나 다른 멤버 함수를 가질 수 없으며 오로지 추상 함수만 가진다.
    • 정말 인터페이스의 역할만 하는 것이다.
      • 자식 클래스에게 이러 이러한 기능들을 꼭 너네들 방식으로 꼭꼭 구현해라! 라는 인터페이스적인 의미만 가지고 있다.
      • 자식 클래스들에게 자신만의 구체적인 데이터를 그대로 물려주는건 단 하나도 없다. 오로지 추상함수들만 가지기 때문이다.
        • 👉 그래서 인터페이스를 다중 상속할 수 있다. 그대로 물려주는게 하나도 없기 때문에 자식들은 무조건 오버라이딩을 해야 한다. 따라서 인터페이스를 다중 상속 받을 땐 죽음의 다이아몬드 문제가 발생하지 않는다. (선택지를 1️⃣로만 강제함)
          class FlyableOrc : Orc, IFlyable  // 👉 인터페이스를 이렇게 다중 상속하는 것이 가능 ! 
          {
              public void Fly()
              {
                          
              }
          }
          
  • 추상 클래스와 마찬가지로 인터페이스 타입의 객체는 생성할 수 없지만 인터페이스 타입의 변수를 선언하여 자식 타입의 객체를 업캐스팅 할 수는 있다. 👉 다형성
    • 아래 flyable.Fly(); 이 코드 한줄은, flyable이 어떤 자식 타입인지에 따라 각각 다르게 실행될 것이다. 모든 자식들은 자신만의 Fly()로 재정의를 해야하기 때문이다.
          static void DoFly(IFlyable flyable)
          {
              flyable.Fly(); // 아무 문제 없다.
          }
          static void Main(string[] args)
          {
              IFlyable flyable = new IFlyable(); // ❌❌ 컴파일 에러
              IFlyable flyable = new FlyableOrc();  // ⭕ 다형성
          }
      


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

맨 위로 이동하기

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

댓글 남기기