다이아몬드 문제(Diamond Problem):
다중 상속을 허용하면 한 클래스가 두 개 이상의 부모 클래스로부터 동일한 멤버를 상속받을 수 있음. 이 경우, 같은 이름의 멤버를 가지고 있을 때 어떤 부모 클래스의 멤버를 사용해야 하는지 모호해짐. 이런 모호성을 해결하기 위한 규칙이 필요하게 되는데, 이로 인해 코드가 복잡해지고 가독성이 저하될 수 있음
설계의 복잡성 증가:
다중 상속을 허용하면 클래스 간의 관계가 복잡해짐. 클래스가 다중 상속을 받을 경우, 어떤 클래스로부터 어떤 멤버를 상속받을지 결정해야 함. 이로 인해 클래스 간의 상속 관계를 파악하기 어려워지고 코드의 유지 보수성이 저하될 수 있음
이름 충돌과 충돌 해결의 어려움:
다중 상속을 허용하면 여러 부모 클래스로부터 상속받은 멤버들이 이름이 충돌할 수 있음. 이러한 충돌을 해결하기 위해 충돌하는 멤버를 재정의해야 하거나 명시적으로 부모 클래스를 지정해야 할 수 있음. 이는 코드의 복잡성을 증가시키고 오류 발생 가능성을 높임
설계의 일관성과 단순성 유지:
C#은 단일 상속을 통해 설계의 일관성과 단순성을 유지하고자 함. 단일 상속을 통해 클래스 간의 관계를 명확하게 만들고 코드의 가독성과 이해도를 높일 수 있음. 또한 인터페이스를 사용하여 다중 상속이 필요한 경우에도 유사한 기능을 구현할 수 있음
코드의 재사용성:
인터페이스를 사용하면 다른 클래스에서 해당 인터페이스를 구현하여 동일한 기능을 공유할 수 있음. 인터페이스를 통해 다양한 클래스가 동일한 동작을 수행할 수 있으므로 코드의 재사용성이 향상 됨
다중 상속 제공:
C#에서는 클래스는 단일 상속만을 지원하지만, 인터페이스는 다중 상속을 지원함. 클래스가 여러 인터페이스를 구현함으로써 여러 개의 기능을 조합할 수 있음. 다중 상속을 통해 클래스는 더 다양한 동작을 수행할 수 있음
유연한 설계:
인터페이스를 사용하면 클래스와 인터페이스 간에 느슨한 결합을 형성할 수 있음. 클래스는 인터페이스를 구현하기만 하면 되므로, 클래스의 내부 구현에 대한 변경 없이 인터페이스의 동작을 변경하거나 새로운 인터페이스를 추가할 수 있음. 이는 유연하고 확장 가능한 소프트웨어 설계를 가능하게 함
interface IMyInterface
{
void Method1();
int Method2(string str);
}
class MyClass : IMyInterface
{
public void Method1()
{
// 구현
}
public int Method2(string str)
{
// 구현
return 0;
}
}
// 인터페이스 정의하기
public interface IMovable
{
void Move(int x, int y); // 이동 메서드 선언
}
// 인터페이스를 구현하는 클래스 생성하기
public class Player : IMovable
{
public void Move(int x, int y)
{
// 플레이어의 이동 구현
}
}
public class Enemy : IMovable
{
public void Move(int x, int y)
{
// 적의 이동 구현
}
}
//인터페이스를 사용하여 객체 이동하기
IMovable movableObject1 = new Player();
IMovable movableObject2 = new Enemy();
movableObject1.Move(5, 0); // 플레이어 이동
movableObject2.Move(1, 9); // 적 이동
// 아이템을 사용할 수 있는 인터페이스
public interface IUsable
{
void Use();
}
// 아이템 클래스
public class Item : IUsable
{
public string Name { get; set; }
public void Use()
{
Console.WriteLine("아이템 {0}을 사용했습니다.", Name);
}
}
// 플레이어 클래스
public class Player
{
public void UseItem(IUsable item)
{
item.Use();
}
}
// 게임 실행
static void Main()
{
Player player = new Player();
Item item = new Item { Name = "Health Potion" };
player.UseItem(item);
}
// 인터페이스 1
public interface IItemPickable
{
void PickUp();
}
// 인터페이스 2
public interface IDroppable
{
void Drop();
}
// 아이템 클래스
public class Item : IItemPickable, IDroppable
{
public string Name { get; set; }
public void PickUp()
{
Console.WriteLine("아이템 {0}을 주웠습니다.", Name);
}
public void Drop()
{
Console.WriteLine("아이템 {0}을 버렸습니다.", Name);
}
}
// 플레이어 클래스
public class Player
{
public void InteractWithItem(IItemPickable item)
{
item.PickUp();
}
public void DropItem(IDroppable item)
{
item.Drop();
}
}
// 게임 실행
static void Main()
{
Player player = new Player();
Item item = new Item { Name = "Sword" };
// 아이템 주울 수 있음
player.InteractWithItem(item);
// 아이템 버릴 수 있음
player.DropItem(item);
}
public interface IAnimal
{
void Speak();
}
public class Dog : IAnimal
{
public void Speak()
{
Console.WriteLine("Bark");
}
}
public class Cat : IAnimal
{
public void Speak()
{
Console.WriteLine("Meow");
}
}
IAnimal myDog = new Dog();
IAnimal myCat = new Cat();
myDog.Speak(); // 출력: Bark
myCat.Speak(); // 출력: Meow
Dog myDog = new Dog();
myDog.Speak(); // 출력: Bark
public interface IAnimal
{
void Speak();
}
public class Dog : IAnimal
{
public void Speak()
{
Console.WriteLine("Bark");
}
}
public class Cat : IAnimal
{
public void Speak()
{
Console.WriteLine("Meow");
}
}
public class Cow : IAnimal
{
public void Speak()
{
Console.WriteLine("Moo");
}
}
class Program
{
static void Main(string[] args)
{
IAnimal animal; // IAnimal 인터페이스 타입으로 변수 선언
// animal 변수는 IAnimal 인터페이스 타입으로 선언되었지만,
// Dog, Cat, Cow 클래스의 객체를 모두 가질 수 있음
animal = new Dog();
animal.Speak(); // 출력: Bark
animal = new Cat();
animal.Speak(); // 출력: Meow
animal = new Cow();
animal.Speak(); // 출력: Moo
}
}
// 추상클래스 예시
public abstract class Animal
{
public abstract void Speak(); // 자식 클래스에서 반드시 구현해야 함
public void Sleep() // 구현된 메서드
{
Console.WriteLine("Sleeping...");
}
}
// 인터페이스 예시
public interface IAnimal
{
void Speak(); // 구현 없이 선언만
}
// 인터페이스 예시
public class Dog : IAnimal, IRunnable
{
public void Speak()
{
Console.WriteLine("Bark");
}
public void Run()
{
Console.WriteLine("Running...");
}
}
// 추상클래스 예시
public abstract class Animal
{
public string Name { get; set; } // 프로퍼티
}
// 인터페이스 예시
public interface IAnimal
{
string Name { get; set; } // 프로퍼티만 선언 가능
}
// 추상클래스 예시
public abstract class Animal
{
protected abstract void Speak(); // protected 접근자 가능
}
사용 목적
성능
요약
// 열거형 구현
enum MyEnum
{
Value1,
Value2,
Value3
}
열거형 사용
MyEnum myEnum = MyEnum.Value1;
enum MyEnum
{
Value1 = 10,
Value2, // 11
Value3 = 20
}
int intValue = (int)MyEnum.Value1; // 열거형 값을 정수로 변환
MyEnum enumValue = (MyEnum)intValue; // 정수를 열거형으로 변환
switch(enumValue)
{
case MyEnum.Value1:
// Value1에 대한 처리
break;
case MyEnum.Value2:
// Value2에 대한 처리
break;
case MyEnum.Value3:
// Value3에 대한 처리
break;
default:
// 기본 처리
break;
}
public enum Month
{
Jan = 1,
Feb,
Mar,
Apr,
May,
Jun,
Jul,
Aug,
Sep,
Oct,
Nov,
Dec
}
public static void ProsessMonth(int month)
{
if (month >= (int)Month.Jan && month <= (int)Month.Dec)
{
Month selectMonth = (Month)month;
Console.WriteLine("선택한 월은 {0}입니다.", selectMonth);
}
else
{
Console.WriteLine("올바른 월을 입력해주세요.");
}
}
int userInput = 7;
ProsessMonth(userInput); // 선택한 월은 Jan입니다
enum Color { Red, Green, Blue };
Color myColor = Red; // 정수값 0으로 취급
enum Color : byte { Red, Green, Blue };
Color myColor = Color.Red; // 기본적으로 byte로 처리됨
enum Color { Red, Green, Blue };
int myColor = Red; // Red를 바로 사용 가능
enum Color { Red, Green, Blue };
int myColor = Red; // Red를 바로 사용 가능
enum Color { Red, Green, Blue };
int num = Red; // 암시적 형 변환 가능
int num = (int)Color.Red; // 명시적 캐스팅 필요
enum Permission { Read = 1, Write = 2, Execute = 4 };
[Flags]
enum Permission { Read = 1, Write = 2, Execute = 4 };
Permission myPermission = Permission.Read | Permission.Write;
enum Color : unsigned int { Red = 1, Green = 2, Blue = 3 };
enum Color : byte { Red = 1, Green = 2, Blue = 3 };
class A {
public:
void foo() {
std::cout << "A's foo" << std::endl;
}
};
class B {
public:
void bar() {
std::cout << "B's bar" << std::endl;
}
};
class C : public A, public B {
// A와 B 둘 다 상속받음
};
int main() {
C obj;
obj.foo(); // A의 메서드 호출
obj.bar(); // B의 메서드 호출
}
class A {
public:
void foo() {
std::cout << "A's foo" << std::endl;
}
};
class B : public A {};
class C : public A {};
class D : public B, public C {};
int main() {
D obj;
obj.foo(); // 다이아몬드 문제: A의 foo가 B를 통해서인지 C를 통해서인지를 모호함
}
public interface IAnimal {
void Speak();
}
public interface IRunnable {
void Run();
}
public class Dog : IAnimal, IRunnable {
public void Speak() {
Console.WriteLine("Bark");
}
public void Run() {
Console.WriteLine("Running");
}
}