추상 클래스로 정의된 경우 new를 사용해 스스로 객체가 될 수 없고 추상 메서드를 가질 수 있다. (일반 메서드 또한 당연히 가질 수 있다.)
abstract class AbstractClass
{
public abstract void AbstractMethod();
public void GeneralMethod()
{
Console.WriteLine("General Method");
}
}
AbstractClass test = new AbstractClass(); // 컴파일 에러
구현되지 않은 가상 메서드이다.
일반 클래스에서 선언할 수 없고 추상 클래스에서만 선언할 수 있다. (인터페이스에서도 가능하긴 하지만 딱히 의미가 없다.)
가상 메서드와 다른 점은 자식 클래스에서 재정의가 강제된다는 것이다.
class Test : AbstractClass
{
public override void AbstractMethod()
{
}
}
클래스 문법과 비슷하게 정의하지만 인터페이스는 클래스가 아니며, 0개 이상의 메서드의 선언만 포함할 수 있다. (프로퍼티는 내부적으론 메서드로 구현되므로 인터페이스에 포함될 수 있다.)
스스로 객체가 될 수 없다는 점, 상속 받은 클래스가 멤버를 반드시 구현해야 된다는 점이 추상 클래스와 유사하다.
비록 인터페이스 자체는 객체가 될 수 없지만 인터페이스를 상속 받은 객체는 인터페이스로서 접근이 가능하다.
interface IWalkable
{
void Walk();
}
class Person : IWalkable
{
public void Walk()
{
Console.WriteLine("Walk");
}
}
IWalkable walkable = new Person();
walkable.Walk();
또한 인터페이스는 그 자체로서도 의미를 갖는다.
빈 인터페이스를 상속하여 클래스를 분류할 수 있다.
interface IWalkable {}
class Person : IWalkable
{
public void Walk()
{
Console.WriteLine("Walk");
}
}
class Fish
{
public void Walk()
{
Console.WriteLine("Can't Walk");
}
}
Person person = new Person();
Fish fish = new Fish();
if (person is IWalkable) // True
{
person.Walk();
}
if (fish is IWalkable) // False
{
fish.Walk();
}
인터페이스를 다중 상속할 경우 메서드의 시그니처가 겹치는 경우가 생길 수 있다.
이 경우 인터페이스를 구현하는 과정에서 메서드의 정의가 겹쳐서 특정 인터페이스만의 기능을 구현할 수 없게 된다.
public interface IControl
{
void Paint();
}
public interface ISurface
{
void Paint();
}
public class SampleClass : IControl, ISurface
{
public void Paint()
{
Console.WriteLine("Paint method in SampleClass");
}
}
SampleClass sampleClass = new SampleClass();
IControl control = sampleClass;
ISurface surface = sampleClass;
sampleClass.Paint();
control.Paint();
surface.Paint();
// 출력:
// Paint method in SampleClass
// Paint method in SampleClass
// Paint method in SampleClass
이를 해결하기 위해 C#은 아래와 같이 인터페이스의 메서드를 구현할 때 인터페이스를 명시할 수 있는 기능을 지원한다.
public class SampleClass : IControl, ISurface
{
void IControl.Paint()
{
Console.WriteLine("IControl.Paint");
}
void ISurface.Paint()
{
Console.WriteLine("ISurface.Paint");
}
}
인터페이스를 명시할 경우 기존 표현 방식과 크게 두가지 차이를 가진다.
1. public 접근 제한자를 생략해야 한다.
2. 특정 인터페이스의 기능을 구현했다고 명시했으므로 반드시 형변환을 거쳐야 한다.
SampleClass sampleClass = new SampleClass();
IControl control = sampleClass;
ISurface surface = sampleClass;
sampleClass.Paint(); // 컴파일 에러가 발생한다.
control.Paint();
surface.Paint();
참고 자료
시작하세요! C# 10 프로그래밍 - 정성태