10. Data Abstraction and Object Orientation

Jimin Lim·2021년 12월 6일
0

Programming Language

목록 보기
9/9
post-thumbnail

10. Data Abstraction and Object Orientation

Abstraction: Module, Module types, Class

  • 데이터와 데이터를 처리하는 클래스 제공, 인터페이스를 제공함으로써 추상화

Modules: 여러 개의 함수들을 공유하는 형태, 추상화된 타입을 export
Module Types: 모듈에서는 한 개의 인스턴스만 만들 수 있었는데, 타입을 제공함으로써 여러 개의 인스턴스를 제공한다.
Classes: 관련된 abstraction의 families를 정의해준다.

Difference between modules and module types(classes)

  • 일반적으로 관리자 모듈(rand number 만드는 예시에서 구조체에 seed 변수를 넣어두고 여러 개의 인스턴스를 만들어내도록 했었음)에서 내보낸 명시적 생성 및 소멸 루틴은 모듈 유형의 인스턴스 생성 및 소멸로 대체된다.
  • 특정 모듈 인스턴스의 루틴 호출은 exported type을 함수의 인자로 받아야하는데 모듈 내에 있는 함수로 변경된다. -> 클래스의 멤버 변수를 인자로 전달할 필요가 없어진다.

10.1 Object-Oriented Programming

: 코드 재사용에 중점을 두고 있다.
Dynamic method binding : 다형성

  • earlier(부모) 버전을 예상하지만 새로 만들어진 클래스(자식)를 가능하게 한다.

Fundamental concepts:

  • encapsulation
  • inheritance
  • dynamic method binding (polymorphism)

: 가비지 콜렉션을 지원하지 않아서 아래와 같이 클래스(destructor)를 정의해줘야하는 언어가 존재한다.

//C++
~list() {
	if (!header.singleton())
	throw new list_err("attempt to delete nonempty list"); 
}
//생성자 호출
//C++
list_node elem1(0); //inline object (value 타입)
list_node* p = new list_node(13); //new 사용 (reference 타입) new 를 사용하면 delete로 지워줘야 함

: Public and Private Members

  • public은 구현하는 쪽에서도 보이고, 사용하는 쪽에서도 보인다.
    • pulbic label은 export 된다.
  • 각각 label을 붙이는 언어도 있고, 영역으로 결정하는 언어도 있다.

: C++를 포함한 많은 언어는 초기 declaration에 프로토타입 만을 제공하기도 한다.
: 클래스를 사용하는 사람들에게 보이지 않는 별도의 파일로 제공될 수 있다.

Tiny Subroutines

: OOP는 함수를 호출하거나 짧은 함수들이 많은 경향이 있다.

In C#

class list_node {
    ...
	int val; // private 
    public int Val {
		get { return val; }
		set { val = value; } 
    }
	... 	
}
list_node n:
...
int a = n.Val; // implicit call to get method 
n.Val = 3; // implicit call to set method
  • property mechanism을 제공해서 암시적으로 함수를 호출한다.

Derived Classes

: 상속받은 클래스

 class queue : public list {
 public:
	void enqueue(int v) { 
    append(new list_node(v));
}
int dequeue() { 
	if (empty())
		throw new list_err("attempt to dequeue from empty queue");
	list_node* p = head(); 
    p->remove();
	int v = p->val; 
    delete p;
	return v; 
    }
};
  • queue는 list를 상속받은 자식 클래스
  • base class에서 상속 받고, 베이스에 없는 함수들을 추가할 수 있다.
  • derived class는 base class의 멤버를 redefine할 수 있다.
    • 이때 super, base, 부모클래스 등을 통해서 재정의하기 전을 호출할 수 있다.
  • 2가지 형태로 생각할 수 있다.
    • special kind of list: 상속받는 형태
    • uses a list: list를 포함하는 형태 (권장)

10.2 Encapsulation and Inheritance

10.2.1 Modules

: 유효범위 (Scope rules)를 만드는게 중요한 포인트

  • Clu and Euclid: 선언과 정의가 항상 같이 이루어졌다.
  • Modula-2: 프로그래머가 헤더와 바디를 분리할 수 잇었다.
    • 그러나 헤더를 public과 private으로 나눌 수 없었고, 모두가 public 이었다.
    • data hiding mechanism는 포인터 타입만 export하는 것이며, 이 방식이 최선의 방식이었다. -> pointer로 넘긴다면 어떤 데이터 타입인지 알 수 없도록 한다.
  • Ada: 패키지의 헤더 부분에 public, private을 나눌 수 있도록 해줘서 opaque하게 해줬다.
    • module 헤더의 private 을 바꾸게 된다면 recompilation이 필요했지만 사용자 코드 부분은 수정하지 않아도 된다.
    • header의 pulbic을 수정한다면 사용자 코드 부분도 수정해야한다.

10.2.2 Classes

: 상속을 제공한다.

  • additional issues가 존재한다.

    1. 자식클래스에서 부모클래스의 어디까지 사용할 수 있는지?
    2. 부모클래스의 Private도 자식클래스에 보이도록 할 것인가?
    3. 부모클래스에서 Public 이면 자식클래스에도 Public일 것인지?

    -> C++에서는 해결하고 있다

  • 객체 지향 언어에서는 다른 visible로 접근한다.

    • Eiffel: 자식 클래스에서 멤베에 대해 제한과 확장을 선택적으로 사용할 수 있다.
    • C++: 상속받을 때 부모클래스에 대해 접근을 설정할 수 있다.
    • C#, Java: 자식클래스에서 제한, 확장을 할 수는 없지만 override를 사용해서 안보이게 할 수 있다.
    • Java에서 오버라이드할때, (부모)public -> (자식)private처럼 줄이는 방향으로 못가지만 그 반대는 가능하다.
    • Smalltalk, Objective-C: 어떠한 오브젝트에서, 어떠한 메소드를 가지고 호출하는 지 런타임에서 확인한다.(duck typing)
    • Python: 클래스 멤버는 항상 public
    • Ruby: 항상 필드는 Private, 클래스에 있는 메소드들만 사용가능
  • 객체 지향 언어는 static 필드, 메소드를 허용한다.

    • 클래스 객체가 만들어지지 않아도 접근가능하다.
    • static method는 nonstatic에 접근하지 못한다.
    • 특정 객체에서 변경하면 모두 확인가능하다.

10.2.3 Nesting (Inner Classes)

만약 이너가 아우터의 멤버라면, 이너의 메소드는 아우터의 멤버를 볼 수 있는가?

  • C++, C#: outer의 static member만 접근 가능하다.
  • Java: 각각의 인스턴스의 이너클래스의 멤버가 outer 멤버에 접근할 수 있다.
    • inner class의 각각의 인스턴스들은 outer class의 멤버에 접근하기 위해서 hidden pointer를 전달한다.
    • inner class가 static으로 선언된다면 Static 멤버에만 접근할 수 있다.

10.4 Dynamic Method Binding

: 다형성, C를 상속하는 D가 있을 때, base class를 기대하는 상황에서 derived class를 사용할 수 있다.
: 즉, 공통으로 갖는 형식 매개 변수의 기능만 사용 가능하다. (Parent)

함수 호출 시, 두 가지 방법이 존재한다.
1. 부모에 의거한다 -> static method binding
2. 실제 참조하고 있는 객체에 의거한다 -> dynamic method binding

Semantics and Performance

  • run-time overhead가 발생한다.
  • Smalltalk, Objective-C, Python, Ruby: 모든 메소드에 대해서 dynamic method binding을 제공한다.
  • Java, Eiffel: 기본적으로 dynamic method binding, final/ frozen을 사용해서 override 못하도록 막아준다.
  • Simula, C++, C#, and Ada 95:static method binding이 기본, virtual 키워드를 통해서 dynamic 제공해준다.
    • run time 상에서 어떤 객체를 호출하는지 결정해 줌
    class person { 
    public:
    		virtual void print_mailing_label(); // 함수 앞에 붙여줌
      ...
  • C#: 명확하게 하기 위해서 override, new(redefine) 키워드를 사용해야한다.
  • Java, C++11: override를 필수적으로 붙이는 것은 아니다.

10.4.2 Abstract Classes

: 대부분 객체지향언어에서 virtual method의 바디를 생략할 수 있다.

  • java, C#: abstract
  • C++: virtual =0;
  • 객체를 생성하지 못한다.
  • 목적: 다른 concrete class를 base로 사용하기 위해서
    • hook 의 역할을 한다. 자식 클래스를 구현하는 사람이 구현할 것이라고 믿고 구현한다.

10.4.3 Member Lookup

: static method binding - 컴파일러가 어떤 메소드를 호출할 것인지 타입으로 판단한다.
: dynamic method binding - 가리키는 object는 runtime 시점에 결정된다. -> 각각의 객체의 보이지 않는 필드에 virtual method table의 주소값을 가지고 있는다. 즉, concrete class는 같은 vtable을 공유한다.

  • foo(부모)에다 bar(자식)를 넣을 수 있다.
  • C++의 경우 backword 를 제공한다.
foo F;
bar B;
foo* q;
bar* s;
q = &B; // ok
s = &F; // error
s = dynamic_cast<bar*>(q); // performs a run-time check
//q가 bar 이거나 자식이라면 pointer를 assign 해준다.
  • Java, C#의 경우 강제형변환을 한 후 런타임 체크를 해준다.
  • Eiffel: ?= 타입 맞는지 확인해준다.
  • C#: as
  • Java: instance of
profile
💻 ☕️ 🏝 🍑 🍹 🏊‍♀️

0개의 댓글