클래스 상속 (inheritance)
부모클래스로부터 파생되어 생성된 클래스를 자식클래스 혹은 서브클래스라 부르며, 이때 서브클래스는 부모클래스로부터 클래스 멤버들을 상속받아 사용하게 된다. 클래스 상속(class inheritance)는 객체지향 프로그래밍의 중요한 특징 중의 하나이다.
아래는 TypeScript에서 클래스 상속을 통해 서브클래스를 생성하고 사용하는 예제이다. 즉, Shape는 부모클래스이고, 이를 상속하여 Rectangle이라는 서브클래스를 생성하였다. TypeScript에서 서브클래스를 만들기 위해 (Java와 같이) extends 라는 키워드를 사용하는데, 이는 서브클래스가 부모클래스의 기능을 확장한다는 의미를 갖는다.
아래 예제에서 Rectangle 클래스는 Shape 클래스가 가진 public, protected 멤버를 상속하여 사용할 수 있다. Rectangle의 생성자 constructor()를 보면, name 이라는 입력 파라미터를 super(name) 을 호출하여 부모클래스의 생성자를 호출하고 있는데, 이러한 방식으로 부모클래스의 필드에 값을 전달할 수도 있다.
class Shape { private name: string; public x: number = 0; public y: number = 0; constructor(name: string) { this.name = name; } draw() { console.log("Shape.Draw"); } } class Rectangle extends Shape { public width: number; public height: number; constructor(name: string, width: number, height: number) { super(name); this.width = width; this.height = height; } draw() { console.log("Rectangle " + this.width + " x " + this.height); } isSquare() { return this.width == this.height; } } let rect = new Rectangle("R1", 100, 100); // 부모클래스에서 상속된 속성 사용 rect.x = 50; // // 서브클래스 고유의 속성/메서드 사용 rect.height = 50; let sqr = rect.isSquare(); console.log(sqr); // "false" 출력 // 서브클래스에서 재정의된(override) 메서드 사용 rect.draw(); // "Rectangle 100 x 50" 출력
위 예제에서 보듯이, 서브클래스는 부모클래스로부터 멤버들을 상속받아 사용하면서, 또한 자신의 고유한 속성이나 메서드를 추가로 정의하여 사용한다. 또한, 경우에 따라 부모클래스의 메서드를 재정의(override)하여 사용할 수 있는데, 예를 들어 draw() 메서드는 Shape 클래스에 이미 있지만, 이를 Rectangle 클래스에서 수정하여 새로운 행위를 표현할 수 있다.
추상클래스 (abstract class)
추상클래스 (abstract class)는 다른 서브클래스의 부모클래스 역활을 하는 클래스로서 그로부터 객체를 생성할 수 없는 클래스를 가리킨다. 추상클래스는 class 앞에 abstract 라는 키워드를 표시하며, 이 클래스부터 직접 객체를 생성하는 막는다. 추상클래스 안에는 추상메서드를 정의할 수 있는데, 추상메서드는 메서드명 앞에 abstract 키워드를 표시한 메서드로서 이 메서드는 메서드 본체를 갖지 않고 메서드 원형만을 정의한다. 즉, 이 추상메서드는 서브클래스에서 반드시 정의해서 사용해야 하는 메서드를 의미한다.
아래 예제는 추상클래스의 예로서 Shape 클래스는 추상클래스로 정의되었고, 그 안의 draw() 메서드는 추상메서드로 정의되어 있다. Shape 클래스를 상속하는 Rectangle이나 Circle 클래스는 자신의 클래스에서 draw() 메서드를 구현하여 사용하고 있다. 예제의 마지막 부분에 new Shape()를 통해 Shape 객체를 생성하는 코드가 있는데, Shape는 추상클래스이므로 이 부분은 에러를 발생시키게 된다.
abstract class Shape { private name: string; constructor(name: string) { this.name = name; } abstract draw(); } class Rectangle extends Shape { public width: number; public height: number; constructor(name: string, width: number, height: number) { super(name); this.width = width; this.height = height; } draw() { console.log("Rectangle " + this.width + " x " + this.height); } } class Circle extends Shape { public radius: number; constructor(name: string, radius: number) { super(name); this.radius = radius; } draw() { console.log("Circle " + this.radius); } } let rect = new Rectangle("R", 10, 10); let circ = new Circle("C", 5); // 에러: "Cannot create an instance of an abstract class" let shape = new Shape("S");