본문 바로가기
프로그래밍언어론

[프로그래밍언어론] 31. OOP 개념

by 파스텔코랄 2023. 11. 6.

객체(Object)

  • 객체 : 데이터, 작업을 모두 캡슐화하는 컨테이너
  • ADT 변수 : 해당 데이터만 나타낸다.
    • 변수 자체를 사용하여 작업을 호출
    • void increment(Counter c)
  • 객체의 데이터 항목 : 인스턴스 변수(instance variables)
  • 작업 : 메서드(method)

 



메소드 호출(Method Invocation)

  • 객체에 대한 작업 실행은 객체에 메시지를 전송하여 수행
    • object.method(params)
  • 객체에 대한 메소드 호출
  • 객체에게 메소드를 호출하도록 지시
  • 객체 자체는 메소드의 암시적 매개변수로 간주될 수 있다.

 



클래스(Class)

  • 클래스 : 객체 집합의 모델
  • 클래스가 있는 언어에서는 모든 객체가 클래스에 속한다.
  • 객체는 클래스의 인스턴스로 간주될 수 있다.
    • 객체는 해당 클래스의 인스턴스화에 의해 동적으로 생성된다.
    • 예) Counter c = new Counter();

 



클래스와 객체

  • 메소드는 클래스에 한 번만 저장된다.
  • 각 개체(인스턴스)에는 자체 인스턴스 변수가 포함되어 있다.
  • 클래스의 메소드에 대한 포인터도 객체에 저장된다.
  • 자체 참조의 경우 메서드에서는 this(또는 self)를 사용

 



캡슐화(Encapsulation)

  • public, private
  • 숨겨야 할 정보 : private
  • 일반적으로 데이터와 일부 메소드 : private
  • 인터페이스 역할을 하는 메소드 : public
  • 캡슐화(Encapsulation): 클래스라는 캡슐로 데이터와 작업을 함께 래핑
  • 정보 숨기기(Information hiding) : 캡슐 내부의 세부 정보를 비공개 영역에 배치하여 숨기는 것

 


 

하위 타입(Subtypes)

  • S 인터페이스가 T 인터페이스의 하위 집합인 경우 T는 S의 하위 타입
    • 타입 S의 값이 필요한 곳에 타입 T의 값을 넣어도 아무 문제가 없다면 T는 S의 하위타입이다. 
  • S의 모든 작업은 T에서 가능
  • T는 S의 모든 필드뿐만 아니라 추가 필드를 가질 수도 있다.
class NewCounter extends Counter{
    private int num_reset = 0;
    public int get_reset() {
        return this.num_reset;
    }
}

 



생성자(Constructor)

  • 객체 생성
    • 메모리 할당
    • 개체 데이터의 초기화
  • 후자는 생성자(Constructors)로 수행
  • 클래스와 동일한 이름을 사용하거나 다른 고유한 이름을 사용하는 경우가 많다.
C++, Java

class Counter{
    public Counter() {
        ...
    }
}
Python

class Counter:
    def __init__(self):
        ...


  • 생성자 선택(Constructor  Selection)
    • 클래스에 두 개 이상의 생성자(오버로딩)
    • 어느 것을 사용?
    • C++의 복사 생성자
  • 생성자 체이닝(Constructor Chaining)
    • 슈퍼클래스의 일부는 어떻게/언제 초기화?
    • 어떤 슈퍼클래스 생성자를 어떤 인수로 호출?

 


 

상속(Inheritance)

  • 상속 : 기존 개체의 재사용을 기반으로 새 개체(또는 클래스)를 정의
  • 상속 vs. 하위 타입
    • 상속 : 코드 재사용(reuse, 구현 상속) 가능성
    • 하위 타입 : 호환성(compatibility, 인터페이스 상속)
  • 하위 클래스에 대한 보호 키워드

  • 단일, 다중 상속
    • 하나의 슈퍼클래스를 허용, 아니면 여러 개의 슈퍼클래스를 허용?
  • 다중 상속으로 인해 문제 발생
    • 이름 충돌
    • 다이아몬드 문제

 


 

다이아몬드 문제

  • 어느 f()를 불러야 할지 모르겠다.
  • 한정된 이름으로 메서드를 명시적으로 지정합니다.

 



동적 메소드 조회

  • Counter 예시
  • Counter 및 NewCounter는 클래스에 정의되어 있다.
  • Counter를 재설정하려고 하면 어떻게 할까?
Counter arr[100];
...
arr[9] = new Counter();
arr[10] = new NewCounter();
...
for(int i=0; i<100; i++){
    arr[i].reset();
}

class Counter{
    private int x = 0;
    public void reset() {
        x = 0;
    }
    public void inc() {
        x += 1;
    }
    public int get() {
        return x;
    }
}

class NewCounter extends Counter{
    private int num_reset = 0;
    public void reset() {
        x = 0;
        num_reset += 1;
    }
    public int get_reset() {
        return this.num_reset;
    }
}
  • 컴파일러는 메소드가 호출될 객체의 유형이 무엇인지 결정할 수 없다.
  • 클래스 A에서 f는 g를 호출. 이는 보다 명시적으로 this.g()
  • 따라서 실제 g는 이 지점이 어떤 객체인지에 따라 나중에 실행에서 사용할 수 있다.
    • this, self의 후기 바인딩(late binding)
class A {
    int a = 0;
    void f() { g(); }
    void g() { a = 1; }
}
class B extends A{
    int b = 0;
    void g() { b = 2; }
}

B b = new B();
b.f();

 



메소드 오버라이딩(Overriding) 및 섀도잉(Shadowing)

  • 메소드 오버라이딩(Overriding) : 하위 타입에서 메소드를 재정의
  • 섀도잉(Shadowing) : 하위 타입에서 필드를 재정의
  • 단, 참고하는 경우에는 차이가 있다.
    • 오버라이딩 : 동적(dynamic)
    • 섀도잉 : 정적(static)
public class A {
    public int num = 5;
    public int update() {
        return num-1;
    }
}
public class B extends A {
    public int num = 3;
    public int update() {
        return num+5;
}

B b = new B();
A a = b;
System.out.println(b.num); //3
System.out.println(b.update()); //8
System.out.println(a. num); //5
System.out.println(a.update()); //8

 

댓글