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");
}
}
public class D : B, C
{
}
내 답:
불가능합니다.
C#에서는 클래스의 다중 상속을 허용하지 않습니다.
모범 답:
불가능하다. C#에서는 클래스의 다중상속을 지원하지 않는다. 만약 C와 B가 인터페이스였다면 다중 상속이 가능했을 것이다.
내 답:
다르게 작동하는 override 된 함수 Display()가 중복 존재하게 됩니다.
모범 답:
클래스 B or C를 살펴보면 같은 이름의 메서드가 존재한다. 이런 경우 모호성 문제가 발생할 것이라고 생각한다. 이는 "다이아몬드 문제(Diamond Problem)"라고 불리며, 어떤 Display 메서드를 호출해야 할지 결정하는 데 어려움이 있다.
내 답:
: 기호를 사용해 상속합니다.
모범 답:
클래스를 다른 클래스로 상속하기 위한 방법: : 키워드를 사용하여 상속합니다. 부모 클래스와 자식 클래스의 관계를 설명하고, base 키워드를 통해 부모 클래스의 멤버에 접근할 수 있다고 언급하면 좋습니다.
상속선언을 통해 파생 클래스가 기본 클래스의 모든 공용 및 보호된 멤버를 상속받게 한다.
public class B : A
내 답:
한 클래스가 두 개 이상의 경로를 통해 동일한 기반 클래스로부터 상속을 받을 때 발생하며, 이로 인해 어떤 경로의 기반 클래스 메서드를 호출해야 할 지 모호성이 생기는 것입니다.
C#은 다중 상속을 지원하지 않고, 대신 인터페이스를 사용하여 유사한 기능을 구현합니다. 클래스는 여러 인터페이스를 구현할 수 있지만, 클래스로부터는 직접적으로는 단 하나의 클래스만 상속 가능합니다. 이로 인해 C#에서는 다이아몬드 문제가 발생하지 않습니다.
모범 답:
다중 상속에서 발생하는 문제로, 동일한 부모 클래스를 두 번 상속받아 모호성 문제가 발생합니다. 이를 해결하기 위해 인터페이스 사용과 명시적 구현을 언급하면 좋습니다.
다중 상속을 사용한 객체 지향 프로그래밍에서 발생하는 모호성 문제, 이 문제는 두 개의 클래스가 동일한 기본 클래스를 상속받고, 그 클래스들을 다시 다른 클래스가 상속받을 때 발생한다. C#의 경우에는 원칙적으로 클래스간의 다중상속을 막아 이 문제를 처음부터 예방하고 있다. 그러나 인터페이스는 다중 상속을 지원 하는데 인터페이스간 똑같은 메서드를 가졌다 하더라도 명시적 인터페이스 구현(explicit interface implementation)을 통해 모호성을 해결할 수 있다.
내 답:
인터페이스는 메서드, 속성, 이벤트 등을 정의하지만, 이러한 것들의 구현을 포함하지는 않으며, 상속 받은 클래스가 인터페이스에 정의된 모든 것들을 구현하도록 강제합니다.
모범 답:
메서드 시그니처를 정의하고, 클래스가 이를 구현해야 합니다. 다중 구현이 가능하며, 계약과 추상화를 제공한다고 설명하면 좋습니다.
강제 구현을 통한 함수명의 통일화와 다중 상속을 통해 원하는 기능을 탈부착 하기 위해 사용하는 것, 클래스도 물론 다른 클래스에 상속이 가능하나, 다중 상속이 불가능 하며 이 점이 인터페이스와 가장 큰 차이이다.
내 답:
인터페이스에는 구현부를 포함할 수 없는 대신 클래스에 다중 상속이 가능합니다. 추상 클래스는 구현부가 없는 추상 메서드를 포함하고, 구현된 메서드도 포함 할 수 있지만 클래스에 다중 상속이 불가능합니다.
인터페이스의 모든 멤버의 접근 제한자는 public입니다. 그러나 추상 클래스 내의 멤버들은 다양한 접근 제한자 public, protected, private등을 가질 수 있습니다.
모범 답:
인터페이스는 구현 없음으로 다중 상속이 가능하며, 추상 클래스는 일부 구현을 가지며 단일 상속만 가능합니다. 용도와 확장성에 대해 언급하면 좋습니다.
다중 상속 가능 여부:
인터페이스: 다중 상속이 가능, 한 클래스가 여러 인터페이스를 구현할 수 있다.
추상 클래스: 단일 상속만 가능, 한 클래스는 하나의 추상 클래스만 상속받을 수 있다.
사용 목적:
인터페이스: 특정 행위를 규정하고 계약을 정의하는 데 사용된다. 객체가 무엇을 할 수 있는지를 명시적으로 정의한다.
추상 클래스: 공통된 기본 구현을 제공하며, 관련 클래스 간에 코드를 공유하고 일관된 기본 동작을 제공하기 위해 사용된다.
멤버의 종류:
인터페이스: 인스턴스 필드, 생성자, 소멸자는 가질 수 없다.
추상 클래스: 필드, 생성자, 소멸자, 속성, 메서드 등을 가질 수 있다.
오늘의 날씨를 콘솔에 입력받는 모니터와, 파일에 입력받는 모니터를 각각 만들어봅니다.
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() 함수를 이용합니다.
//public void WriteLog(string message)
//{
// Console.WriteLine($"{DateTime.Now.ToLocalTime()}: {message}");
//}
//public void WriteError(string error)
//{
// WriteLog($"Error: {error}");
//}
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}");
//}
//public void WriteError(string error)
//{
// WriteLog($"Error: {error}");
//}
public void WriteLog(string message)
{
writer.WriteLine($"{DateTime.Now.ToLocalTime()}: {message}");
}
//
}
class ClimateMonitor
{
// TODO : ConsoleLogger또는 FileLogger의 기능을 가질 수 있는 ConsoleMonitor를 작성
public List<ILogger> loggers;
public ClimateMonitor(ILogger logger)
{
loggers = new List<ILogger>();
loggers.Add(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();
}
}