12장: 다형성

다형성의 종류

  • 오버로딩 다형성: 하나의 클래스 안에 동일한 이름의 메서드가 존재하도록 하는 방식

  • 강제 다형성: 언어가 지원하는 자동적인 타입 변환이나 사용자가 직접 구현한 타입 변환을 이용해 동일한 연산자를 다양한 타입에 사용할 수 있는 방식

    • 자바에서 이항 연산자인 ‘+’ 는 피연산자가 모두 정수일 경우에는 정수에 대한 덧셈 연산자로 동작하지만 하나는 정수형이고 다른 하나는 문자열인 경우에는 연결 연산자로 동작한다.

  • 매개변수 다형성: 클래스의 인스턴스 변수나 메서드의 매개변수 타입을 임의의 타입으로 선언한 후 사용하는 시점에 구체적인 타입으로 지정하는 방식 (제네릭 프로그래밍)

    • 자바의 List 인터페이스는 다양한 타입의 요소를 다루기 위해 제네릭을 사용해 구체 타입이 인스턴스 생성 시점에 정해질 수 있도록 한다.

  • 포함(Subtype) 다형성: 메시지가 동일하더라도 수신한 객체의 타입에 따라 실제로 수행되는 행동이 달라지는 능력

    • 객체 지향 프로그래밍에서 가장 널리 알려진 일반적인 형태의 다형성

    • 자식 클래스가 부모 클래스의 서브타입이어야 한다. 이러한 형태를 목적으로 상속을 사용할 수 있다.

상속의 목적과 특징

  • 상속의 목적은 코드 재사용이 아니라 프로그램을 구성하는 개념들을 기반으로 다형성을 가능하게 하는 타입 계층을 구축하기 위한 것이다.

  • 데이터 관점에서 상속은 자식 클래스의 인스턴스 안에 부모 클래스의 인스턴스를 포함하는 것으로 볼 수 있다.

  • 행동 관점의 상속은 부모 클래스가 정의한 일부 메서드를 자식 클래스의 메서드로 포함시키는 것을 의미한다.

  • 정적 바인딩

    • 컴파일 타임에 호출할 함수를 결정하는 것

  • 동적 바인딩

    • 선언된 변수의 타입이 아니라 메시지를 수신하는 객체의 타입에 따라 실행되는 메서드가 결정되는 것

    • 객체지향에서는 메시지를 수신했을 때 실행될 메서드가 런타임에 결정된다. 실행 시점에 어떤 인스턴스를 생성해 전달하는지에 따라 실제 실행되는 메서드가 달라진다.

  • 업캐스팅

    • 부모 클래스(Lecture) 타입으로 선언된 변수에 자식 클래스(GradeLecture)의 인스턴스를 할당하는 것

    • 코드를 변경하지 않고도 기능을 추가할 수 있게 해주며 이것은 개방-폐쇄 원칙의 의도와 일치한다.

  • 다운캐스팅

    • 부모 클래스의 인스턴스를 자식 클래스 타입에 할당하기 위해서는 명시적으로 자식 클래스로 타입 캐스팅 해야한다.

  • 객체지향 언어에서 실행할 메서드를 탐색하는 과정

    1. 메시지를 수신한 객체는 먼저 자신을 생성한 클래스(self 참조)에 적합한 메서드가 존재하는지 검사한다.

    2. 메서드를 찾지 못했다면 부모 클래스(parent 참조)를 타고 따라가며 탐색을 계속한다.

    3. 상속 계층의 가장 최상위 클래스에 도달했지만 메서드를 발견하지 못한 경우 예외를 발생시키며 탐색을 중단한다.

  • 동일한 코드여도 어떤 인스턴스가 할당되는지에 따라 메서드 탐색을 위한 상속 계층의 범위가 동적으로 변한다.

  • 동적 타입 언어는 이해할 수 없는 메시지를 처리할 수 있는 능력을 가짐으로써 메시지가 선언된 인터페이스와 메서드가 정의된 구현을 분리할 수 있다.

  • 정적 타입 언어는 이해할 수 없는 메시지인지 여부를 컴파일 타임에 판단하여 프로그램의 안정성을 높인다.

동적 리셉션: 동적 타입 언어가 정적 타입 언어과 달리 이해할 수 없는 메시지 처리가 가능하여, 정적 타입 언어에 비해 쉽고 강력한 도메인-특화 언어(Domain- Specific Language, DSL)를 개발하는 방식

  • super 참조를 통해 메시지를 전송하는 것은 마치 부모 클래스의 인스턴스에게 메시지를 전송하는 것처럼 보이기 때문에 이를 super 전송(super send)이라고 부른다.

  • self 전송이 메시지를 수신하는 객체의 클래스에 따라 메서드를 탐색할 시작 위치를 동적으로 결정하는 데 비해 super 전송은 항상 메시지를 전송하는 클래스의 부모 클래스에서부터 시작된다.

  • self 전송의 경우 메서드 탐색을 시작할 클래스를 반드시 실행 시점에 동적으로 결정해야 하지만, super 전송의 경우에는 어떤 클래스를 상속받을 지 코드 상으로 결정해두기 때문에 컴파일 시점에 미리 결정해 놓을 수 있다.

  • self 참조는 항상 메시지를 수신한 객체를 가리킨다. 즉, GradeLecture 인스턴스에 포함된 Lecture 인스턴스 입장에서 self 참조는 GradeLecture 인스턴스이다.

  • 위임

    • 자신이 수신한 메시지를 다른 객체에게 동일하게 전달해서 처리를 요청 하는 것

    • 상속 관계로 연결된 클래스 사이에는 자동적인 메시지 위임이 일어난다.

  • 클래스 기반의 객체지향 언어들이 상속을 이용해 클래스 사이에 self 참조를 자동으로 전달하는 것처럼, 클래스가 존재하지 않고 객체만 존재하는 프로토타입 기반의 객체지향 언어는 위임을 이용해 객체 사이에 self 참조를 자동으로 전달할 수 있다.

  • 클래스 없이도 객체 사이의 협력 관계를 구축하는 것이 가능하며 상속 없이도 다형성을 구현하는 것이 가능하다.

Last updated