1. 인터페이스(Interface)란 무엇인가?
인터페이스는 구현되지 않은 메소드, 프로퍼티, 인덱서, 이벤트로 구성된 설계의 표현입니다. 인터페이스는 구체적인 구현 없이 메소드 시그니처만 정의하며, 이 인터페이스를 구현하는 클래스가 그 메소드들을 구체적으로 구현해야 합니다.
주요 특징:
- interface 키워드를 사용하여 선언.
- 다중 상속이 가능함.
- 모든 멤버는 public으로 접근 가능.
- 인터페이스는 객체 자체를 가질 수 없으며, 구현되지 않은 기능만을 정의.
인터페이스 선언 예시:
interface IShape {
void Draw();
double Area();
}
2. 인터페이스의 구현
인터페이스는 클래스를 통해 구현되며, 인터페이스에 정의된 모든 멤버를 구현해야 합니다. 만약 하나라도 구현하지 않으면 그 클래스는 추상 클래스가 됩니다.
인터페이스 구현 예시:
class Rectangle : IShape {
public void Draw() {
Console.WriteLine("Drawing a rectangle");
}
public double Area() {
return 20.0;
}
}
3. 다중 상속과 인터페이스 확장
C#에서 인터페이스는 다중 상속이 가능합니다. 즉, 하나의 클래스가 여러 개의 인터페이스를 구현할 수 있으며, 인터페이스끼리도 확장될 수 있습니다.
다중 상속 예시:
interface IRectangle {
void Area(int width, int height);
}
interface ITriangle {
void Area(int width, int height);
}
class Shape : IRectangle, ITriangle {
void IRectangle.Area(int width, int height) {
Console.WriteLine("Rectangle Area: " + width * height);
}
void ITriangle.Area(int width, int height) {
Console.WriteLine("Triangle Area: " + (width * height) / 2);
}
}
4. 캐스팅을 통한 인터페이스 접근
인터페이스에서 선언된 멤버를 사용할 때 명시적으로 캐스팅하여 사용할 수 있습니다. 인터페이스가 동일한 이름의 메소드를 제공할 경우, 어떤 인터페이스의 메소드를 호출할 것인지 명확히 하기 위해 캐스팅이 필요합니다.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ImplementingInterfaceApp
{
interface IRectangle
{
void Area(int width, int height);
}
interface ITriangle
{
void Area(int width, int height);
}
class Shape : IRectangle, ITriangle
{
//[명시적 인터페이스 구현]
void IRectangle.Area(int width, int height)
{
Console.WriteLine("Rectangle Area : " + width * height);
}
void ITriangle.Area(int width, int height)
{
Console.WriteLine("Triangle Area : " + width * height / 2);
}
}
class Program
{
public static void Main()
{
Shape s = new Shape();
// s.Area(10, 10); // error - ambiguous !!!
// s.IRectangle.Area(10, 10); // error
// s.ITriangle.Area(10, 10); // error
((IRectangle)s).Area(20, 20); // 캐스팅-업
((ITriangle)s).Area(20, 20); // 캐스팅-업
IRectangle r = s; // 인터페이스로 캐스팅-업
ITriangle t = s; // 인터페이스로 캐스팅-업
r.Area(30, 30);
t.Area(30, 30);
}
}
}
캐스팅 방법은 두 가지로 나눌 수 있습니다. 두 방법 모두 인터페이스를 통해 명시적 인터페이스 구현 메소드를 호출할 수 있게 합니다. 차이점은 즉시 캐스팅이냐 변수에 할당 후 캐스팅이냐에 있습니다.
1. 즉시 캐스팅 (Inline Casting)
이 방법은 한 줄에서 직접 객체를 캐스팅하고, 그 캐스팅된 인터페이스를 통해 메소드를 호출하는 방식입니다.
예시:
((IRectangle)s).Area(20, 20); // 즉시 캐스팅하여 메소드 호출
설명:
(IRectangle)
:s
객체를IRectangle
인터페이스로 캐스팅합니다.- 캐스팅된 객체로 즉시 메소드 호출이 가능합니다.
- 한 줄에서 캐스팅과 호출이 동시에 이루어지며, 이 방식은 일시적으로만 해당 인터페이스 타입으로 객체를 사용할 때 주로 사용됩니다.
2. 변수에 할당 후 캐스팅
이 방법은 객체를 먼저 인터페이스 타입의 변수에 캐스팅하여 저장한 후, 해당 변수를 사용하여 인터페이스 메소드를 호출하는 방식입니다.
예시:
IRectangle r = s; // 객체를 IRectangle 타입으로 캐스팅하여 저장
r.Area(30, 30); // 변수를 통해 메소드 호출
설명:
IRectangle r = s;
:s
객체를IRectangle
타입으로 캐스팅하고, 그 결과를r
변수에 저장합니다.- 이후
r
변수를 통해 메소드를 호출할 수 있습니다. - 이 방법은 여러 번 해당 인터페이스의 메소드를 호출하거나, 캐스팅된 객체를 반복적으로 사용할 경우에 적합합니다.
두 방식의 차이점
방법 | 설명 | 사용 시점 |
---|---|---|
즉시 캐스팅 (Inline Casting) | 한 줄에서 즉시 객체를 캐스팅하고 메소드를 호출합니다. | 한 번만 메소드를 호출하거나 일시적으로만 사용할 때 적합 |
변수에 할당 후 캐스팅 | 객체를 변수에 캐스팅하여 저장하고, 여러 번 호출하거나 반복적으로 사용할 때 유용합니다. | 여러 번 해당 인터페이스 메소드를 호출할 필요가 있을 때 적합 |
예시 비교:
1. 즉시 캐스팅 (Inline Casting)
((IRectangle)s).Area(20, 20); // 캐스팅 후 즉시 메소드 호출
2. 변수에 할당 후 캐스팅
IRectangle r = s; // 객체를 인터페이스 타입으로 캐스팅하여 변수에 저장
r.Area(30, 30); // 변수를 사용하여 메소드 호출
언제 각각의 방법을 사용할까?
- 즉시 캐스팅은 간단한 상황에서, 특정 메소드를 한 번만 호출할 때 주로 사용됩니다.
- 예를 들어, 특정 메소드를 한 번만 실행하고 더 이상 사용할 일이 없는 경우에 적합합니다.
- 변수에 할당 후 캐스팅은 같은 객체를 반복적으로 사용하거나, 인터페이스 타입의 메소드를 여러 번 호출할 때 사용됩니다.
- 변수를 사용하면 코드 가독성도 좋아지고, 반복적인 캐스팅을 피할 수 있습니다.
요약:
두 방식 모두 인터페이스를 통해 명시적 구현 메소드를 호출할 수 있으며, 선택은 상황에 따라 달라집니다.
- 즉시 캐스팅: 객체를 한 번만 캐스팅하고 바로 메소드를 호출할 때 적합.
- 변수에 할당 후 캐스팅: 여러 번 메소드를 호출하거나 캐스팅된 객체를 반복적으로 사용할 때 적합.
💡 캐스팅이 필요한 이유
: 캐스팅을 통해서만 메소드에 접근할 수 있는 이유는, 명시적 인터페이스 구현을 사용하면 클래스 자체의 인스턴스에서 해당 메소드가 보이지 않기 때문입니다. 즉, 인터페이스 타입으로 캐스팅하지 않으면 클래스 인스턴스는 이 메소드를 직접 호출할 수 없습니다.
5. 다이아몬드 상속 문제
인터페이스에서 다중 상속이 가능하기 때문에, 다이아몬드 상속 문제가 발생할 수 있습니다. 예를 들어, 인터페이스 IX를 상속한 두 클래스가 IX의 메소드를 재정의할 때, 그 하위 클래스는 어느 버전의 메소드를 사용할지 혼란이 발생할 수 있습니다.
다이아몬드 상속 예시:
interface IX { void XMethod(int i); }
interface IY : IX { void YMethod(int i); }
class A : IX {
public void XMethod(int i) { /* ... */ }
}
class B : A, IY {
public void YMethod(int i) { /* ... */ }
}
6. 인터페이스와 추상 클래스의 차이점
- 인터페이스는 오직 메소드 시그니처만 제공하고, 다중 상속을 지원하며, 메소드 구현 시
override
키워드를 사용할 수 없습니다. - 추상 클래스는 단일 상속만 지원하며, 메소드의 일부 구현을 제공할 수 있고, 메소드 재정의 시
override
키워드를 사용해야 합니다.
7. 네임스페이스(Namespace)
네임스페이스는 관련된 클래스, 인터페이스, 구조체 등을 그룹화하는 단위입니다. 네임스페이스는 클래스 이름 충돌을 방지하는 데 유용하며, 다양한 코드를 모듈화하여 관리할 수 있습니다.
네임스페이스 사용 예시:
namespace ShapesNamespace {
class Circle {
public void Draw() {
Console.WriteLine("Drawing a Circle");
}
}
}
'2학년 2학기 > 윈도우즈 프로그래밍' 카테고리의 다른 글
윈폼 블로그 (3) | 2024.11.04 |
---|---|
고급 프로그래밍 기법(1) - 제너릭, Attribute (0) | 2024.09.30 |
인터페이스(1) - 파생 클래스, 메소드 오버라이딩, 추상 클래스 (0) | 2024.09.30 |
클래스(2) - 메소드 / 연산자 오버로딩, 생성자, 인덱서, 프로퍼티 (0) | 2024.09.30 |
클래스(1) - 클래스 선언, 생성, 필드, 메소드 (0) | 2024.09.30 |