객체지향 프로그래밍 언어의 3가지 특징
- Abstract Data Types: 추상 자료형
- Inheritance: 상속
- Polymorphism: 다형성
Inheritance 상속
- 재사용이 가능하므로 생산성이 높아진다.
- ADT의 문제점이 모든 인스턴스가 독립적이고 동등하므로 재사용을 하기 어렵다는 것이었다.
- 이미 존재하는 것의 속성을 가져와 새로운 클래스를 정의하는 것을 허용한다.
👉🏻 ADT의 사소한 부분을 수정해 계층적으로 새로운 클래스를 정의해 재사용할 수 있도록 한다. (상속의 계층 구조)
- 유지보수가 어렵다는 단점이 있다. 부모가 바뀌면 자식들까지 모두 수정해야 하기 때문이다.
Object-Oriented Concepts 객체지향의 개념
기본적으로 자식 클래스는 부모 클래스의 전부를 상속받지만, 캡슐화된 요소에 대한 접근 제어를 통해 좀 더 복잡한 구조를 가질 수 있다.
- 클래스의 요소를 자식 클래스에게 보이지 않도록 할 수 있다. (private)
- 클래스의 요소를 디폴트 패키지 범위에서만 보이게 하며, 클라이언트(이 클래스를 사용하는 다른 클래스)에게 보이지 않도록 할 수 있다. (default)
- 클래스의 요소를 클라이언트에게 보이지 않도록 하면서, 자신을 상속한 자식 클래스에게는 보이게 할 수 있다. (protected)
또한, 클래스는 자신이 상속받은 클래스의 메서드를 수정(override)하여 사용할 수 있다. 변수나 메서드를 새롭게 추가할 수도 있다.
클래스의 변수는 클래스 변수(static)와 인스턴스 변수의 2가지로 나눌 수 있다. 클래스 변수는 클래스 당 1개만 존재하며, 인스턴스 변수는 객체 당 1개가 존재한다. 클래스의 메서드 또한 클래스 메서드와 인스턴스 메서드로 나뉘며, 클래스 메서드는 별도의 객체 생성 없이도 사용 가능하다. 반면에 인스턴스 메서드는 메서드의 목표가 될 객체가 생성되어야 사용할 수 있다.
Dynamic Binding 동적 바인딩
- Polymorpic variable: 어떠한 클래스의 인스턴스뿐만 아니라 그 클래스를 상속받은 모든 클래스의 인스턴스까지 참조할 수 있는 변수를 말한다.
// B가 A를 extend할 때
A x = new B();
// x: polymorpic variable
- Abstract class: 하나 이상의 virtual method를 갖는 클래스를 가리킨다. 인스턴스화할 수 없다.
- Abstract method: 프로토콜만 정의되어 있으며 정의부는 작성되지 않은 메서드를 가리킨다.
The Exclusivity of Object 객체의 배타성
- 모든 것을 객체로 만들어 정의했을 때
- 장점: 객체에 메세지를 전달하는 형태이므로 순수하며 우아(?)하다.
- 단점: 간단한 객체라고 하더라도 연산 속도가 느리다. (Dynamic binding & Type checking)
- 명령형 시스템에 객체를 추가했을 때
- 명령형 언어가 갖는 모든 것을 수용한 경우. 명령형 언어 + 객체 개념
- 장점: 간단한 타입에 대한 연산 속도가 빠르다.
- 단점: 기존 타이핑 시스템인지 객체인지 구분하기 어려워진다.
- 원시 타입들은 기본 타입 시스템으로, 나머지는 객체로 취급할 때 (Java)
- 장점: 간단한 객체에 대해서 빠른 연산 가능하며, 상대적으로 작은 타이핑 시스템 규모를 갖는다.
- 단점: 두가지 타입 시스템을 가지므로 혼동이 올 수 있다.
Are Subclasses Subtypes? 하위 클래스를 하위 타입으로 볼 수 있는가?
부모 클래스로부터 파생된 클래스가 부모 클래스와 똑같이 행동할 때 is-a realtionship을 갖는다. 파생된 클래스가 부모 클래스와 is-a relationship을 갖는다면 파생된 클래스는 부모 클래스의 subtype이다. 하위 클래스가 하위 타입처럼 사용되면 부모는 어떠한 정보도 숨길 수 없게 된다.
똑같이 행동해야 한다고 해서 부모의 멤버를 아예 수정하지 말아야 한다는 건 아니고, 부모의 동작을 벗어나지 않는 선에서, 부모와 호환 가능한(compatible) 선에서 수정 가능하다.
Single and Multiple Inheritance 단일, 다중 상속
- 다중 상속: 여러 부모로부터 상속받는 것
- 장점: 편리하다!
- 단점: 코드와 구현이 복잡해지고, 이름 충돌이 발생할 가능성이 있다. 또, 단일 상속 시보다 동적 바인딩 비용이 더 발생할 수 있다.
Allocation and Deallocation of Objects 객체의 할당과 회수
- 객체를 어디에 할당할 것인가?
- 객체가 기본적인 ADT처럼 사용된다면 어디든지 할당될 수 있다. 보통 런타임 스택에 할당되며, new 키워드를 통해 힙 메모리(동적 메모리 공간)에 명시적으로 생성될 수도 있다.
- 객체들이 모두 heap-dynamic하다면, 참조 변수나 포인터를 통해 참고할 수 있다.
- 객체들이 모두 stack-dynamic하다면, subtype으로 취급했을 때 바인딩 관련 문제가 발생한다.
- 회수는 명시적으로, 혹은 묵시적으로 실행되는가?
Dynamic and Static binding 동적, 정적 바인딩
- 모든 객체에 대한 메세지 바인딩은 동적이어야 하는가?
- 그렇게 된다면 겁나 비효율적이며, 그렇지 않다면 동적 바인딩의 장점을 다 쌈싸먹고 있는 것이다.
- 어쩌라고?
- 바인딩에 대한 디자인은 개발자가 결정하도록 하는 게 좋다.
Nested Classes 중첩 클래스
- 만약 새로운 클래스가 오직 한 개의 클래스에서 사용된다면, 굳이 다른 클래스에서도 사용할 수 있도록 정의하지 않아도 된다.
- 어떤 경우에는 새로운 클래스가 서브프로그램 안에 중첩되기도 한다. (Java의 익명 클래스)
Initialization of Objects 객체 초기화
- 객체가 생성될 때 객체의 값들이 초기화되는가?
- 하위 클래스의 객체가 생성될 때 부모 클래스의 멤버들은 어떻게 초기화되는가?
Support for Object-Oriented Programming in Some Languages
1. Smalltalk
- 상속: 모든 하위 클래스는 하위 타입이다. 부모와 자식이 똑같이 행동하며, 부모의 멤버를 자식에게 숨길 수 없다. 다중 상속은 불가능하다.
- 동적 바인딩: 모든 메세지-메서드 바인딩은 동적으로 이루어진다. 타입 검사는 동적으로 이루어지며, 메세지를 존재하지 않는 메서드와 바인딩하려 하는 경우에만 타입 에러가 발생한다.
2. C++
- 특징: C와 SIMULA 67을 발전시킨 형태다. 순수 OOP가 아닌 Mixed typing system을 갖는다.
- 상속
- 모든 클래스는 어떤 클래스의 하위 클래스일 필요가 없다(cf. Java).
- 멤버에 대하여 private, public, protected 의 키워드를 통한 접근 제어가 가능하다.
- 상속 시 하위 클래스에서도 접근 제어가 가능하다.
- private derivation: 상속받은 public, protected 멤버들은 하위 클래스에서 private해진다.
- public derivation: 상속받은 public, protected 멤버들은 하위 클래스에서도 public, protected하다.
- Reexportation: private derivation으로 인해 하위 클래스에서 접근이 불가능해진 부모의 멤버는 resolution operator(::)을 통해 접근할 수 있다. :: 왼쪽에는 namespace가 온다.
- 다중 상속이 가능하다.
- 동적 바인딩
- 메서드는 virtual 키워드와 함께 정의될 수 있으며, 이렇게 정의된 메서드는 polymorphic variables를 통해 호출할 수 있고, 동적으로 메세지에 바인딩된다.
- 순수 virtual 함수는 정의부가 존재하지 않는다.
- 하나 이상의 순수 virtual 함수를 갖는 클래스를 abstract class라고 부른다.
// heap memory에 선언 Square* sq = new Square; Rectangle* rect = new Rectangle; Shape* ptr_shape; ptr_shape = sq; ptr_shape->draw(); // Dynamic binding rect->draw(); // Static binding // stack memory에 선언 Square sq; Rectangle rect; rect = sq; // 동적으로 할당되는 것이 아닌 단순 복사임 rect.draw() // Rectangle의 draw()가 실행됨
3. Java
- 특징: C++와 유사하며, 원시 타입을 제외한 모든 데이터는 객체다. 원시 타입도 객체처럼 사용할 수 있게 wrapper class를 제공한다. 모든 객체는 heap-dynamic하며, 보통 new 키워드와 함께 할당된다. 순차적 프로그래밍은 지원하지 않으며 모든 코드는 항상 클래스 안에 있다.
- 상속
- 클래스에 대해서는 단일 상속만 지원하지만, 여러 개의 인터페이스를 상속받는 것은 가능하다.
- 인터페이스 -> 인터페이스 다중상속 가능
- 클래스 -> 인터페이스 다중상속 가능
- 클래스 -> 클래스 다중상속 불가능
- 인터페이스는 오직 메서드 선언부와 상수의 이름만 가질 수 있다.
- 메서드는 final 키워드를 가질 수 있으며, 자식 클래스에서 override할 수 없다. 모든 메서드가 final이면 이 경우 subclass를 subtype으로 사용할 수 있다.
- 클래스에 대해서는 단일 상속만 지원하지만, 여러 개의 인터페이스를 상속받는 것은 가능하다.
- 동적 바인딩: 메서드가 final, static, private하지 않은 경우 메세지는 메서드에 동적으로 바인딩된다. 쟤네들을 달고 있으면 오버라이딩이 불가능하므로 동적 바인딩이 의미가 없다.
- 중첩 클래스: 중첩 클래스를 지원하며, 직접적으로 중첩된 non-static 클래스들을 innerclass라고 하며, 바깥 클래스의 멤버에 접근할 수 있다. (static한 중첩된 클래스는 바깥 클래스의 멤버에 접근할 수 없다.) 중첩된 클래스는 익명일 수 있다.
4. C#
- 특징: 클래스, 구조체(stack-dynamic)를 지원한다. C++의 문법을 사용해 클래스를 정의할 수 있다. Java의 super처럼 base 키워드를 통해 부모의 멤버에 접근할 수 있다. 부모의 멤버 중 private한 멤버가 없다면 하위 클래스들은 하위 타입이다. 단일 상속만 가능하다.
- 동적 바인딩
- 베이스 클래스의 메서드가 virtual로 마크되어 있어야 하며, 파생 클래스에서는 해당 메서드가 override로 마크되어 있어야 동적 바인딩이 가능하다.
- 추상 메서드들은 abstract 로 마크되어 있으며, 모든 하위 클래스에서 구현해야 한다.
- 모든 C# 클래스들은 Object 클래스의 하위 클래스다.
- 중첩 클래스: C#의 중첩 클래스들은 Java의 static nested class처럼 동작한다.
'강의노트' 카테고리의 다른 글
[2021-1 운영체제] Chapter 3: 프로세스와 스레드 (1) | 2021.06.18 |
---|---|
[2021-1 프로그래밍언어론] Chapter 14: Exception Handling and Event Handling (0) | 2021.06.01 |
[2021-1 프로그래밍언어론] Chapter 11: Abstract Data Types and Encapsulation Constructs (0) | 2021.06.01 |
[2021-1 프로그래밍언어론] Chapter 10: Implementing Subprograms (0) | 2021.05.30 |
[2021-1 데이터마이닝및분석] Chapter 2: Data (3) Similarity (0) | 2021.04.16 |