: 추상은 구체적이지 않다는 뜻으로 추상 클래스란 구체적인지 않은 클래스, 즉 완성되지 않은 클래스라고 말할 수 있다.
추상클래스란 선언은 했으나 구현 내용이 없는 클래스로 추상 메소드를 한개라도 포함하고 있는 클래스
추상 메소드는 선언부만 있고, 구현부가 없는 메소드로 구현은 자식 클래스에서 반드시 구현해야한다.
virtual을 붙이지 않아도 항상 가상이다.
메소드 앞에 abstract 키워드가 붙어 잇으면 명시적인 추상 메소드로, 본체가 구현되어 있지 않아 구체적인 동작을 정의하지 않고 호출할 수도 없다.
사용 문법
접근 지정자 abstract 데이터형 메소드 이름();
자식 클래스에서 재정의(overriding)해야 호출 가능한 메소드이다.
추상 메소드 작성 예시
public abstract void Network();
클래스 선언 시 abstract 키워드를 붙임으로써 추상 클래스를 선언 가능하며, 객체를 생성할 수 없는 클래스이다.
추상 클래스를 선언하고, 그 추상 클래스를 상속받아 재정의하는 형태로 사용한다.
abstract class 추상클래스 이름
{
접근지정자 abstract 데이터형 메소드이름();
}
class 자식클래스이름 : 추상클래스이름(부모클래스)
{
접근지정자 override 데이터형 메소드이름()
{
메소드 기능 정의
}
}
위 기본형태를 예시코드로 작성해보면 아래와 같다
abstract class SmartPhone
{
public abstract void Network();
}
class ACompany : SmartPhone
{
public override void Network()
{
메소드 기능 정의
}
}
그런데 이러한 추상 클래스는 도대체 왜 사용하는 것일까??
자식 단계에서 어떠한 기능을 구현할 지 상세하게 정의가 되지 않은 상태, 즉 설계단계에서 표준(=골격)만 정의할 때 추상 클래스를 사용한다.
단순하게 말하면 설계 단계에서의 blue-print(청사진)와 같다고 볼 수 있는 것이다.
추상 클래스는 기능들은 표준이지만, 구현 방식은 각 회사마다 다르며, 스마트폰 자체는 구체적인 기능을 결정할 수 없다.
따라서 설계자는 기능의 표준만 정의(추상 클래스)해주고, 구현은 각 회사의 몫으로 넘긴다.
namespace 추상클래스
{
abstract class SmartPhone
{
public abstract void Network();
public abstract void CallPhone();
public abstract void Camera();
}
class Samsung:SmartPhone
{
public override void Network()
{
Console.WriteLine("네트워크가 연결되었습니다.");
}
public override void CallPhone()
{
Console.WriteLine("통화가 연결되었습니다.");
}
public override void Camera()
{
Console.WriteLine("카메라가 모드를 변경했습니다.");
}
}
internal class Program
{
static void Main(string[] args)
{
Samsung sm = new Samsung();
sm.Network();
sm.CallPhone();
sm.Camera();
SmartPhone com = new Samsung();
com.Network();
com.CallPhone();
com.Camera();
}
}
}
위 코드의 결과값은 동일하다.
하지만, Samsung이라는 데이터 타입을 가진 sm과 SmartPhone이라는 데이터 타입을 가진 com의 차이는 무엇일까??
Samsung의 sm은 Samsung클래스 타입을 가지며, Samsung 클래스의 모든 멤버와 메소드에 접근할 수 있다. 따라서, SmartPhone에 정의되지 않고, Samsung클래스에 추가적으로 정의된 메소드가 존재하더라도 sm은 접근 및 호출이 가능한 반면 com은 Samsung의 객체를 참조하고 있지만 SmartPhone타입이다. 따라서 컴파일러는 com을 SmartPhone타입으로 인식하기 때문에 SmartPhone 추상 클래스에서 정의된 멤버들만 사용할 수 있고 sm과 달리 Samsung클래스에서 추가적으로 정의된 메소드에 접근 및 호출이 불가하다.
메소드 앞에 sealed 지정자를 붙이면 재정의할 수 없는 봉인 메소드가 되는데, 기능이 확정되어 더 수정할 필요가 없을 정도로 완벽한 클래스를 의미한다.
namespace sealedClass
{
class Base
{
public virtual void Message()
{
Console.WriteLine("Base");
}
}
class Derived : Base
{
public sealed override void Message()
{
Console.WriteLine("Derived");
}
}
class Thrid:Derived
{
public new void Message()
{
Console.WriteLine("Third");
}
}
internal class Program
{
static void Main(string[] args)
{
Base b = new Base();
b = new Derived();
b.Message();
Thrid th = new Thrid();
th.Message();
}
}
}
위 코드와 같이 클래스 sealed를 붙여 봉인을 하면 해당 메소드를 상속받더라도 override를 할 수가 없다.
따라서, 해당 메소드를 사용하기 위해서는 "new" 키워드를 통해 다시 메소드를 정의할 필요가 있다.
이렇게 클래스를 봉인하는 이유는 궁극적으로는 해킹 방지 목적으로 해당 기능을 수정하지 못하도록 하기 위해 사용하며, Thread와 같은 기능에서 사용하는 것도 결국은 기능의 override를 방지하는 것이 목적이다.
인터페이스란 메소드의 목록만들을 가지고 있는 명세(Specification)로 형태는 추상 클래스와 같이 메소드의 목록만 선언하고, 구현은 하지 않는다.
클래스의 상속 관계처럼 다른 인터페이로부터 상속이 가능하다.
접근지정자 interface 이름:기반 인터페이스 {}
접근지정자 class 자식클래스이름:인터페이스 {}
인터페이스 예시 코드
namespace 인터페이스
{
public interface IUnit
{
void Attack();
void Move();
}
public class Zergling:IUnit
{
public void Attack()
{
Console.WriteLine("저글링: 공격");
}
public void Move()
{
Console.WriteLine("저글링: 이동");
}
}
public class Dragon : IUnit
{
public void Attack()
{
Console.WriteLine("드라곤: 공격");
}
public void Move()
{
Console.WriteLine("드라곤: 이동");
}
}
internal class Program
{
static void Main(string[] args)
{
Zergling z = new Zergling(); // 클래스는 객체 생성 가능 (인터페이스가 불가능)
z.Attack(); // 저글링: 공격
z.Move(); // 저글링: 이동
Dragon dragon = new Dragon();
dragon.Attack(); // 드라곤: 공격
dragon.Move(); // 드라곤: 이동
}
}
}
해당 내용은 리펙토링의 내용을 기반으로 작성된 내용이니, 혹시 이해가 안된다면 리펙토링의 내용을 다시 확인해주세요.
**다중상속**
: 여러 개의 클래스를 상속받는 것 (C++은 다중 상속이 가능하며, 자바나 C#은 단일 상속만 가능하다. 대신 다중 인터페이스를 상속할 수 있다.)원래 클래스는 하나의 책임만을 가진다는 대명제를 유지하는데, 이러한 관점에서 상속으로 이루어진 클래스 트리 전체는 하나의 책임으로 묶인다.
인터페이스 상속 또는 다중 상속을 하는 경우 두 개의 책임을 지게 되는 것이니 하나의 책임을 지는 룰에 위배될 수 있으나, 클래스 상속과 인터페이스 상속은 그 의미가 분명히 다르다.
클래스 상속은 부모와 자식 간의 같은 책임을 가지지만 작동 형태가 다른 것이라면, 인터페이스 상속은 기능을 추가하거나 클래스 간의 통신을 하기 위한 방법을 제공하는 것이다.