Unity 개발일지

[C#] 상속과 인터페이스 실습하기 본문

C#

[C#] 상속과 인터페이스 실습하기

아머르 2024. 7. 5. 10:45

[확인문제]

 

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

더보기

C#에서는 다중 상속이 불가능하다. C#은 다중 상속을 지원하지 않으며, 그 이유는 다중 상속이 복잡성과 모호성을 초래할 수 있기 때문이다. 특히, 여러 기본 클래스가 동일한 메서드를 구현할 경우 어떤 메서드를 상속받아야 할지 모호해진다.

 

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

더보기

클래스 D는 "다이아몬드 문제"에 직면하게 된다. 이는 B와 C가 동일한 부모 클래스 A를 상속받고, D가 B와 C를 상속받을 때 발생한다. B와 C가 A의 동일한 메서드를 오버라이드할 경우, D는 어떤 메서드를 상속받아야 할지 모호해진다.

 

[설명 문제]

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

더보기

클래스 이름 뒤에 콜론(:) 을 붙이고, 이어서 상속받을 클래스 이름을 작성하여 상속한다.

 

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

더보기

다이아몬드 문제는 두 클래스(B와 C)가 공통의 부모 클래스(A)를 상속받고, 또 다른 클래스(D)가 이 두 클래스를 상속받을 때 발생한다. B와 C가 A의 동일한 메서드를 오버라이드 하면, D는 어떤 메서드를 상속받아야 할지 모호해지며 이 문제는 인터페이스를 이용하여 해결할 수 있다. 인터페이스는 구현 없이 메서드 시그니처만 정의하기 때문에 다중 상속의 모호성을 피할 수 있다.

 

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

더보기

인터페이스는 클래스가 구현해야 하는 메서드와 속성을 정의한다. 인터페이스는 구현을 포함하지 않고, 단지 멤버의 선언만 포함한다. 인터페이스를 구현하는 클래스는 인터페이스에 정의된 모든 멤버를 구현해야 한다.

 

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

더보기

인터페이스 : 메서드, 속성, 이벤트 또는 인덱서를 선언만 하고 구현하지 않는다. 클래스는 여러 인터페이스를 구현할 수 있다.

추상 클래스 : 선언과 함께 구현을 포함할 수 있다. 필드, 생성자, 메서드 등의 구현을 포함할 수 있으며, 한 클래스는 오직 하나의 추상 클래스를 상속받을 수 있다.

 

 

[실습 문제]

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

 

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

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

 

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

 

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

 

더보기
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
{
    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;
    }

    public void WriteLog(string message)
    {
        writer.WriteLine($"{DateTime.Now.ToLocalTime()} {message}");
    }
}

class ClimateMonitor
{
    // 인터페이스를 구현한 Logger 리스트 선언
    private List<ILogger> loggers;
    
    // 초기 Logger들을 받아서 리스트에 생성
    public ClimateMonitor(params ILogger[] initialLoggers)
    {
        loggers = new List<ILogger>(initialLoggers)
    }

    // 새로운 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();
    }
}

* DateTime.Now : 현재 시스템의 날짜와 시간을 나타내는 DateTime 객체를 반환, 이는 시스템의 로컬 시간대로 설정된 현재 시간을 포함

* ToLocalTime() 메서드 : UTC(세계 표준시) 시간을 로컬 시간대로 변환

* writer.WriteLine() : StreamWriter 클래스의 메서드로, 지정된 텍스트를 텍스트 파일에 기록하고, 줄바꿈 추가

* SteamWriter : 텍스트 파일에 대한 쓰기 작업을 쉽게 수행할 수 있도록 돕는 클래스

* params : C#에서 사용되는 특수한 매개변수로, 메서드에 가변 개수의 인수(배열)를 전달할 수 있게 해준다.

 

반응형