스파르타 게임개발종합반(Unity)/기술 면접 대비 꾸준 실습

05. 상속과 인터페이스

테크러너 2024. 7. 8.

확인 문제

using System;

// 상위 클래스 A
public class A
{
    public virtual void Display()
    {
        Console.WriteLine("Class A Display");
    }
}

// 클래스 B는 클래스 A를 상속받음
public class B : A
{
    public override void Display()
    {
        Console.WriteLine("Class B Display");
    }
}

// 클래스 C는 클래스 A를 상속받음
public class C : A
{
    public override void Display()
    {
        Console.WriteLine("Class C Display");
    }
}

 

1. 위와 같은 코드에서, 다음과 같이 다중 상속을 하는 것이 가능할까요? 가능/불가능하다면 이유는 무엇일까요?

public class D : B, C
{
    
}

불가능합니다. C#에서는 다중 상속을 지원하지 않습니다. 다이아몬드 문제라고 불리는 모호성 문제 때문입니다. 예를 들어, 두 부모 클래스가 같은 조상을 가지고 있을 때, 어떤 부모 클래스의 메서드를 상속받을지 결정하기 어려운 상황이 발생할 수 있습니다. 이를 다이아몬드 문제라고 합니다.

다중 상속 대신 인터페이스를 사용하면 됩니다. 인터페이스는 클래스가 여러개를 구현할 수 있도록 하여 다중 상속의 일부 장점을 제공합니다.

 

 

2. 만약 C#에서 다중 상속이 지원되었다면, 클래스 D는 어떤 문제에 직면하게 될까요?

B,C 두 부모 클래스가 A라는 같은 조상을 가지고 있기 때문에 어떤 부모 클래스의 메서드를 상속받을지 결정하기 어렵게 됩니다.

 

 

설명 문제

1. 클래스를 다른 클래스로 상속하기 위한 방법은 무엇인가요?

: 키워드를 사용합니다. Ex) 자식클래스 : 부모클래스

 

2. 클래스 상속에서 다이아몬드 문제(diamond problem)가 발생하는 이유와 이를 해결하는 방법에 대해 설명해주세요.

두 부모 클래스가 같은 조상을 가지고 있을 때, 어떤 부모 클래스의 메서드를 상속받을지 결정하기 어려운 상황이 발생할 수 있습니다.

다중 상속 대신 인터페이스를 사용하면 됩니다. 인터페이스는 클래스가 여러개를 구현할 수 있도록 하여 다중 상속의 일부 장점을 제공합니다.

 

3. 인터페이스란 무엇인가요?

인터페이스는 클래스나 구조체가 특정 기능을 구현하도록 강제하는 일종의 계약을 정의하는 것입니다. 인터페이스의 멤버는 구현되지 않고 선언만 됩니다. 인터페이스를 구현하는 클래스나 구조체는 이들 멤버를 구현해야 합니다.

 

++ C# 8.0 이후로 인터페이스에서도 일부 구현을 포함할 수 있는 기능이 추가되었습니다. 기본 구현(Default Interface Methods)이라고 불리며, 인터페이스에서 메서드에 기본 구현을 제공할 수 있게 합니다. 이렇게 하면 인터페이스를 구현하는 클래스에서 해당 메서드를 반드시 구현하지 않아도 됩니다.

public interface ILogger
{
    void WriteLog(string message);

    void WriteError(string error)
    {
        WriteLog($"Error: {error}");
    }
}

 

4. 인터페이스와 추상클래스의 차이는 무엇인가요?

클래스는 여러 개의 인터페이스를 구현할 수 있는데, 추상 클래스는 하나만 상속받을 수 있습니다.

인터페이스는 선언부만 있고, 구현을 포함하지 않습니다. 추상 클래스는 추상 메서드와 일반 메서드를 모두 포함할 수 있는데, 추상 메서드는 인터페이스와 마찬가지로 선언만 하고 구현을 포함하지 않습니다.

인터페이스의 모든 멤버는 public이며, 다른 접근 제한자를 사용할 수 없습니다. 추상 클래스는 다양한 접근제한자를 사용할 수 있습니다.

인터페이스는 생성자를 가질 수 없습니다. 추상 클래스는 생성자를 가질 수 있습니다.

인터페이스는 필드(멤버 변수)를 가질 수 없습니다. 추상 클래스는 필드를 가질 수 있습니다.

 

 

실습 문제

💡 [Climate Monitor 구현]

오늘의 날씨를 콘솔에 입력받는 모니터와, 파일에 입력받는 모니터를 각각 만들어봅니다.

`ConsoleLogger` : 콘솔에 온도를 기록하는 클래스

`FileLogger` : 파일에 온도를 기록하는 클래스

 

⚠️주의!!!)

조건 : `ClimateMonitor` 클래스는 `ConsoleLogger`와 `FileLogger`를 직접 참조할 수 없도록 합니다.

 

ConsoleLogger, FileLogger 구현 시 다음의 인터페이스를 상속받아 제작합니다.

interface ILogger
{
    void WriteLog(string message);
    void WriteError(string error)
    {
        WriteLog($"Error: {error}");
    }
}

 

 

using System;
using System.IO;
using System.Collections.Generic;

interface ILogger
{
    void WriteLog(string message);
    void WriteError(string error)
    {
        WriteLog($"Error: {error}");
    }
}

class ConsoleLogger : ILogger
{
    // TODO : ConsoleLogger가 현재 시간과 메시지를 콘솔에 출력하는 기능을 추가
    // HINT : DateTime.Now.ToLocalTime() 함수를 이용합니다.
    
    //
}

class FileLogger : ILogger
{
    private StreamWriter writer;

    public FileLogger(string path)
    {
        writer = File.CreateText(path);
        writer.AutoFlush = true;
    }

    // TODO : FileLogger가 현재 시간과 메시지를 파일에 기록하는 기능을 추가
    // HINT : writer.WriteLine() 함수를 이용합니다.
    
    //
}

class ClimateMonitor
{
    // TODO : ConsoleLogger또는 FileLogger의 기능을 가질 수 있는 ConsoleMonitor를 작성
    
    //

    public void Start()
    {
        while (true)
        {
            Console.Write("온도를 입력해주세요. : ");
            string temperature = Console.ReadLine();
            if (temperature == "")
            {
                WriteAllError("공백을 입력받았습니다.");
                break;
            }

            WriteAllLog("현재 온도 : " + temperature);
        }
    }

    private void WriteAllLog(string message)
    {
        foreach (var logger in loggers)
            logger.WriteLog(message);
    }

    private void WriteAllError(string error)
    {
        foreach (var logger in loggers)
            logger.WriteError(error);
    }
}

class Program
{
    static void Main(string[] args)
    {
        ClimateMonitor monitor = new ClimateMonitor(new ConsoleLogger());
        monitor.Start();

        Console.WriteLine("이제부터 파일에도 기록됩니다.");

        monitor.AddLogger(new FileLogger("MyLog.txt"));
        monitor.Start();
    }
}

 

 

구현한 코드▼

더보기
interface ILogger
{
    void WriteLog(string message);
    void WriteError(string error)
    {
        WriteLog($"Error: {error}");
    }
}

class ConsoleLogger : ILogger
{
    // TODO : ConsoleLogger가 현재 시간과 메시지를 콘솔에 출력하는 기능을 추가
    // HINT : DateTime.Now.ToLocalTime() 함수를 이용합니다.
    public void WriteLog(string message)
    {
        Console.WriteLine($"{DateTime.Now.ToLocalTime()} {message}");
    }
    //
}

class FileLogger : ILogger
{
    private StreamWriter writer;

    public FileLogger(string path)
    {
        writer = File.CreateText(path);
        writer.AutoFlush = true;
    }

    // TODO : FileLogger가 현재 시간과 메시지를 파일에 기록하는 기능을 추가
    // HINT : writer.WriteLine() 함수를 이용합니다.
    public void WriteLog(string message)
    {
        writer.WriteLine($"{DateTime.Now.ToLocalTime()} {message}");
    }
    //
}

class ClimateMonitor
{
    // TODO : ConsoleLogger또는 FileLogger의 기능을 가질 수 있는 ConsoleMonitor를 작성
    private List<ILogger> loggers;

    public ClimateMonitor(ILogger logger)
    {
        loggers = new List<ILogger> { logger };
    }
    public void AddLogger(ILogger logger)
    {
        loggers.Add(logger);
    }
    //

    public void Start()
    {
        while (true)
        {
            Console.Write("온도를 입력해주세요. : ");
            string temperature = Console.ReadLine();
            if (temperature == "")
            {
                WriteAllError("공백을 입력받았습니다.");
                break;
            }

            WriteAllLog("현재 온도 : " + temperature);
        }
    }

    private void WriteAllLog(string message)
    {
        foreach (var logger in loggers)
            logger.WriteLog(message);
    }

    private void WriteAllError(string error)
    {
        foreach (var logger in loggers)
            logger.WriteError(error);
    }
}

class Program
{
    static void Main(string[] args)
    {
        ClimateMonitor monitor = new ClimateMonitor(new ConsoleLogger());
        monitor.Start();

        Console.WriteLine("이제부터 파일에도 기록됩니다.");

        monitor.AddLogger(new FileLogger("MyLog.txt"));
        monitor.Start();
    }
}
반응형

댓글