- 객체지향 프로그래밍

리문·2022년 5월 30일
0

객체지향 프로그래밍


  • 현대 프로그래밍 패러다임 중 가장 주류가 된 프로그래밍 패러다임.
  • 객체 위주로 프로그래밍 (절차지향 프로그래밍은 프로시저(함수))
  • 객체 : 데이터 영역 (변수)

절차지향 프로그래밍의 한계

  1. 데이터와 데이터를 다루는 함수가 분리.

    • 첫번째 인자로 어떤 변수를 사용할 지 주소값을 매번 지정해줘야 했음.
    • 함수가 길어짐.
    • 함수 내부에서도 포인터로 데이터를 다뤄야함.
  2. 함수의 이름을 항상 다르게 작성해야 한다.

    • 전역 이름공간을 사용하기에 모든 함수마다 이름을 다르게 지어줘야 함.
  3. 프로그램을 확장하기 불편하다.

    • 프로그램이 커질수록 기능구현 < 버그수정(유지보수).
    • 절차지향은 프로그램에 수정 사항이 생기면 변경 사항이 많아짐 (필요한 함수를 명확하게 호출해야 하기 때문에).
    • so, 유지보수가 점점 어려워짐.

객체지향 프로그래밍의 주요 개념

  • 캡슐화 : 데이터와 데이터를 다루는 함수를 같이 작성하는 것.

    • 작성

      • 절차지향 => 어떤 타입의 객체를 만들기 위해서 하나의 함수를 만들어야한다.
      • 객체지향 => 어떤 객체를 생성하는 생성자라는 특수한 함수를 이용한다.
      • 더 이상 포인터 변수를 작성할 필요가 없고, this 포인터라는 특수 포인터로 대체된다.
      • this 포인터 : 매개변수가 암시적으로 변환 했을 때, 매개변수의 주소값을 알려주는 포인터. 매개변수의 역할을 하기 때문에 크기가 없음.
    • 사용

      • 절차지향 => 객체를 초기화하기 위한 함수를 호출하고, 첫 번째 인자로 객체의 주소값 필요.
      • 객체지향 => 좀 더 직관적인 초기화 가능. 객체를 이용해 함수 호출 가능.
        • 접근한정자 : 객체를 올바르게 사용할 수 있도록 존재. 외부에 공개할 것과 그렇지 않을 것을 구분 지을 수 있다. -> 객체지향에서는 외부접근이 불가능하여 컴파일 오류 (오류를 확인할 수 있다).
          • public : 외부에서 접근 가능.
          • protected : 클래스 내부 및 자식 클래스만 접근 가능.
          • private : 내부에서만 접근 가능.
  • 객체지향 프로그래밍에서 데이터 부분을 필드, 함수를 메소드라고 한다.

  • 상속 : 코드를 물려받는 것. 코드 재사용.
    - 객체지향에서는 상속을 이용하여 중복을 줄이고, 타입을 더 작은 단위로 모듈화 할 수 있다.

  • 추상화 : 구현 세부 정보를 숨기는 일반적인 인터페이스정의하는 행위.
    - 구현 세부 사항에 변화가 생겨도 사용하는 방식에는 달라지는 것이 없기 때문에 확장성도 가지게 됨.
    - 추상화를 잘하면 잘할수록 데이터를 다루기 쉬워짐.

        > 인터페이스 : 서로 다른 부분이 만나고 소통하거나 서로에게 영향을 미치는 영역. 
        ex) 전등을 킬 때 전기회로를 몰라도 스위치를 사용할 수 있음. 스위치 = 인터페이스.
  • 다형성 : 여러가지 형태를 가지는 것.
    - 다형성을 이용하려면 가상함수가 필요함.
    - 가상 함수를 이용하려면 상위 타입의 포인터를 이용해야함.
    - 같은 인터페이스 내에서 여러가지 형태를 띌 수 있음.
    - 때문에, 다형성은 객체지향 프로그래밍의 핵심이라고 할 수 있다.


C++프로그래밍


레퍼런스

  • 포인터 타입처럼 간접 참조를 위한 타입.
  • 포인터의 2가지 불편함을 해소하기 위해 등장.
    • 포인터는 널(NULL) 값이 포함 될 수 있다.
    • 간접 참조로 데이터를 다루기 위해선 역참조 연산자를 사용해야함.
  • NULL값이 들어올 수 없기 때문에 NULL 체크를 하지 않아도 된다. -> 반드시 초기화 필요.
  • 주소연산 불가능.

클래스

  • 클래스 타입. struct, class, union.
  • 클래스 내부에서 선언된 식별자는 클래스 범위를 가진다.
  • 인스턴스 : A a <- a는 A에 대한 인스턴스 (모든 인스턴스 -> 객체 AND 모든 객체 -> 인스턴스 x).
  • 접근 한정자 제공 -> public, protected, private.
  • class의 기본 접근 지정자 = private.
  • 생성자 : 인스턴스의 초기화를 담당하는 메소드. 반환 타입 없음. 멤버 초기화 목록이라는 특정한 문법을 지님.
    - 변환 생성자 : 기본적으로 모든 생성자는 변환 생성자이다. 생성자에 사용한 매개변수 목록에서 클래스 타입으로 암시적 변환이 일어난다.

    A() : //이 부분이 멤버 초기화 목록. data(0).
    {
    // 초기화 외에 인스턴스를 만들면서 해야할 일.
    }


  • 기본 메소드 : 클래스 타입이 기본적으로 갖고 있는 메소드.
    • 기본 생성자
      • 매개변수가 없는 생성자.
      • 기본 생성자가 생성되는 경우 (컴파일러가 자동으로 생성해줌)
        - 생성자를 정의해주지 않았을 때.
        - 멤버중 클래스 타입이 있을 때.
        ex) A() { } 형태
    • 복사생성자
      • 생성자 중 동일 타입의 레퍼런스를 인자로 받는 생성자.
      • 기본 생성자와 마찬가지로 복사 생성자가 없으면 자동으로 합성됨.
      • 멤버에 포인터가 있는 경우 주의해야함.
        • 얕은 복사 : 서로 다른 인스턴스임에도, 같은 메모리를 가리키고 있는 것.
        • 깊은 복사 : 서로 다른 메모리 영역을 가리키면서, 데이터는 똑같게 만들어 준 것.
    • 소멸자
      • 객체의 수명이 다할 때 자동으로 호출되는 특수한 메소드.
      • 자원을 정리하기 위해 사용됨.
      • 반환 타입 없음.
      • 타입 이름 앞에 ~
      • 매개변수 적지 않음.
      • RAII(Resource Acquisition Is Initialization).
      • 소멸자도 정의되지 않으면 소멸자가 자동으로 컴파일러에 의해 합성됨. BUT, 아무런 효과도 없음.
- 복사 할당 연산자 : 연산자 오버로딩 중 하나의 매개변수만 가지며, 그 매개변수의 타입이 클래스 타입과 동일한 할당 연산자 = 연산자를 이용하여 복사하기 위함.

- 이동 생성자

- 이동 할당 연산자
  • 기본 메소드에 대해서는 default나 delete 를 이용하여 컴파일러가 생성해주는 함수를 사용하거나 삭제할 수 있다.

  • 비정적 멤버 (인스턴스 멤버)
    • 각 인스턴스에서 사용하는 멤버
  • 정적 멤버

    • 멤버를 사용할 때, static 키워드를 붙이면 정적 멤버가 됨.
    • 프로세스 주소 공간 중, 데이터 영역을 사용.
    • 각 영역마다 하나씩 존재.
  • explicit 한정자

    • 매개변수가 하나인 생성자가 있으면, 암시적 변환이 일어남. -> 의도치 않은 결과를 발생시킴.
    • explicit(명시적) 한정자로 암시적 변환을 막아줌.
  • 오버로딩

    • 절차지향에서는 식별자의 이름을 항상 다르게 적어줘야 했음.
    • 객체지향에서는 오버로딩이라는 기능을 제공함.
    • 오버로딩 : 함수의 식별자를 같게 적어도 됨.
    • but, 매개변수 목록이 달라야 함 (매개 변수 목록으로 식별하기 때문).

  • 상속
    • 생성부모 클래스부터, 소멸자식 클래스부터 이루어짐.
      • public 상속 : 부모 클래스의 모든 public 멤버를 자식클래스의 public 멤버로 만들고, 부모 클래스의 모든 protected 멤버를 자식클래스의 protected 멤버로 만든다.
    • 다중 상속 : 여러개 상속 받는 것 가능. ,로 나눔
      • 죽음의 다이아몬드 : 다중 상속 받는 부모 클래스 들에 같은 식별자의 함수가 있다면, 어떤 것을 호출할지 모호하여 컴파일 오류가 나는 것.

  • 가상 함수
    • 다형성을 지원하기 위한 기능.
    • 메소드 앞에 virtual을 적어주면 됨.
    • 오버라이딩 : 가상 함수의 내용을 재정의하는 것.
    • 상속 관계에 있는 클래스 끼리는 변환가능.
    • 업캐스팅(upcasting) : 자식 클래스에서 부모 클래스로 암시적(implicit) 변환이 일어남.
    • 다형성을 사용하려면 부모 클래스 타입을 가리키는 포인터나 레퍼런스로 업캐스팅(upcasting) 해줘야함.
      • 정적 바인딩 : 프로그램 시작 전부터 무엇을 호출할지 정해져있음.
      • 동적 바인딩 : 어떤 것을 호출 할지는 실행 시간 중에 결정됨.
      • 가상함수는 동적 바인딩으로 동작함.
    • 가상함수 테이블 : 동적 바인딩을 위하여 가상 함수의 주소가 저장되어 있음. 각 타입마다 존재.
    • 가상함수 포인터 : 각 인스턴스마다 존재. 자기 타입의 가상함수 테이블을 가리킴.

  • 추상 클래스

    • 인스턴스를 만들 수 없는 클래스
    • 상위 타입을 정의하는 데 사용한다.
    • 순수 가상 함수
      • 가상함수() = 0 으로 사용.
      • 순수 가상 함수를 가진 클래스를 추상 클래스라고 함.
      • 하위 타입으로 하여금 오버라이딩을 강제함 -> 순수 가상 함수를 오버라이딩 하지 않으면 상속받는 클래스도 추상 클래스가 됨 *** 구체 클래스가 되려면 필수적으로 오버라이딩 해야함.
  • 동적 할당

    • 절차지향과 달리 객체를 생성할 때, 생성자와 소멸자를 호출해야함 -> 동적할당의 방식이 달라짐.
    • new / delete 로 동적할당.
    • 내부에서는 malloc과 free를 사용 -> but, 생성자와 소멸자를 만들어주는 코드가 자동으로 삽입됨.(new와 delete에서 나오는건 아님.)
  • 가상 소멸자

    • 업캐스팅 할 때, 객체의 소멸이 제대로 되지 않음.
    • 가상 함수를 사용하여 가상 소멸자를 정의해주면, 제대로 인스턴스가 소멸함.
    • 따라서 상위 클래스가 될 가능성이 있다면, 가상 소멸자를 정의해주어야함.

객체지향적 설계

- 메소드 : 기능. 
- 필드 : 메소드의 상태, 기능 구현을 위한 데이터. 
  • 어떤 기능이 필요한 지 먼저 생각하고, 그 기능 구현을 위해 어떤 데이터가 필요한 지 생각해야함.

  • 책임 주도 설계

    • 협력 : 요청과 응답으로 이루어 짐.
      • 요청
        • 상대방이 문제를 해결할 수 있을 것이라고 생각하고 요청하게 됨.
        • 협력의 성공은 특정 역할을 맡은 각 개인이 얼마나 요청을 이행할 수 있는가에 달려있음.
      • 따라서 객체지향 설계는 적절한 객체에게 적잘한 책임을 부여하는 것에서 시작된다.
  • 객체

    • 상태와 행동을 함께 지닌 실체
    • 객체가 어떤 행동을 해야한다면, 그 객체의 상태도 함께 지니고 있는 것을 뜻함.
    • 좋은 객체가 갖춰야할 요소
      1. 객체는 충분히 협력적이어야 함. -> 다른 객체의 요청을 잘 응답하고, 다른 객체에 협력을 요청해야함.
      2. 객체는 충분히 자율적이어야 한다. -> 요청의 응답하는 방식, 요청에 응할지 여부들도 객체 스스로 결정해야함. 스스로 객체의 내부를 관리하고, 외부의 간섭을 차단해야함.
  • 책임 (역할)

    • 객체가 어떤 행동을 하는 유일한 이유는 다른 객체로부터 요청을 수신했기 때문에.
    • 요청을 처리하기 위해 객체가 수행하는 행동.
    • 객체지향적 설계에서는 기능을 수행할 수 있게 여러 책임으로 나누고 각 개체에 부여하여 협력하게 만들어야 한다.
    • 따라서, 책임은 객체가 어떻게 해야 하는가가 아니라 무엇을 해야 하는가를 설명 해야함. -> 책임은 너무 구체적이어도 안됨(수행 방법에 제한), 너무 추상적이어도 안됨(의도를 명확하게 표현불가.)
  • 메시지

    • 객체지향에서 도움을 요청하는 방법 (유일)
    • 협력은 메시지를 전송하는 객체와 수신하는 객체 사이의 관계로 구성.
    • 송신자(메시지는 전송하는 객체)
    • 수신자(메시지를 수신하는 객체)
    • 메시지를 처리하는 방법을 메소드라고 한다.
    • 메시지와 요청을 처리하기 위한 메소드를 분리하는 것이 객체의 자율성을 높이는 핵심이다.
  • 다형성에 대한 재해석

    • 서로 다른 객체들이 다형성을 만족시킨다는 것은 객체들이 동일한 책임을 공유하는 것.
    • 어떠한 방법이든, 수신자가 메시지를 받을 수 있기만 하면 됨.
    • 따라서 메시지는 송신자와 수신자 사이의 결합도를 낮춤으로써 설계를 유연하고, 확장 가능하고, 재사용 가능하게 만들기 때문에, 훌륭한 메시지가 설계의 품질을 높인다고 할 수 있다.
  • 정리

    • 객체지향이란 시스템을 상호작용하는 자율적인 객체들의 공동체로 바라보고 객체를 이용해 시스템을 분할하는 방법
    • 자율적인 객체란 상태와 행위를 함께 지니며 스스로 자기 자신을 책임지는 객체를 의미
    • 객체는 시스템의 행위를 구현하기 위해 다른 객체와 협력한다. 각 객체는 협력 내에서 정해진 역할을 수행하며 역할은 관련된 책임의 집합이다.
    • 객체는 다른 객체와 협력하기 위해 메시지를 전송하고 메시지를 수신한 객체는 메시지를 처리하는 데 적합한 메소드를 자율적을 선택한다.
    • 코드를 담는 클래스의 관점에서 메시지를 주고 받는 객체의 관점으로 사고의 중심을 전환해야함.
  • SOLID

    • 클린 아키텍처에서 소개된 객체지향 설계의 바탕이 되는 5가지 원칙

      • 단일 책임 원칙 (Single Responsibility Principle)

        • 각 소프트웨어 모듈은 변경의 이유하나여야함.
      • 개방 - 폐쇄 원칙 (Open - Closed Principle)

        • 객체는 확장에는 열려 있어야하고, 변경에는 닫혀 있어야함.
        • 수정보다는 새로운 코드를 추가하는 방식으로 변경하도록 설계되어야함.
        • 데이터가 아닌 메소드를 다뤄서 변경해야함.
      • 리스코프 치환 원칙 (Liskov Substitution Principle)

        • 프로그램 P에서 T타입의 객체 자리에 S타입의 객체로 모두 변경 해도, P의 행위가 변하지 않는다면 S는 T의 하위 타입이다.
        • is-a의 관계 : 7612 is a bus. -> 상속 가능, car is a bus -> 상속 불가능.
        • 부모 클래스는 일반적인 인터페이스만 정의되어 있기 때문에 추상적이므로.
      • 인터페이스 분리 원칙 (Interface Segregation Principle)

        • 결합도 수준메시지 수준으로 낮춘 협력 관계를 구축해야함.
      • 의존성 역전 원칙 (Dependency Inversion Principle)

        • 고수준 정책 구현 코드저수준 세부사항 구현 코드에 절대로 의존해서는 안됨.
        • 따라서, 다형성을 적극적으로 사용해야한다.

템플릿

  • 함수

    • 함수를 선언할 때 기본인자를 전달 가능.
      • 기본 인자는 가장 오른쪽 부터 전달 가능.
  • 일반화 프로그래밍

    • 타입에 관계없이 알고리즘을 기술하는 프로그래밍 패러다임
    • cpp에서는 템플릿이라는 기능으로 일반화 프로그래밍을 지원함.
  • 템플릿

    • 매개변수 목록에 인자 전달.

    • 이것을 특정 타입으로 대체한다고 하여, 특수화라고 함.

    • 클래스 템플릿

    • 함수 템플릿

      • <>를 생략 가능.
    • 템플릿은 템플릿 파라미터와 함께 매개변수화 됨.

      • 비 타입 파라미터
        • 구체적인 타입을 지정.
        • 정수형, 포인터, 레퍼런스
      • 타입 파라미터
        • 타입을 받을 수 있다.
      • 템플릿 파라미터
    • 타입도 인자처럼 전달할 수 있다.

    • 특수화

      • 특수화컴파일 타임에 일어나며, 컴파일러가 템플릿을 기반으로 특정 타입을 생성.
      • 템플릿은 헤더 파일에 모든 내용을 적으며, 정의를 소스 파일에 나눠 적으면 링크 오류가 발생함.
      • 명시적 특수화 : 모든 파라미터에 대해 특수화 하는 것
      • 부분 특수화 : 부분만 특수화

관련문서

profile
개발자되기 대작전

0개의 댓글