객체지향 프로그래밍
- 현대 프로그래밍 패러다임 중 가장 주류가 된 프로그래밍 패러다임.
- 객체 위주로 프로그래밍 (절차지향 프로그래밍은 프로시저(함수))
- 객체 : 데이터 영역 (변수)
절차지향 프로그래밍의 한계
-
데이터와 데이터를 다루는 함수가 분리.
- 첫번째 인자로 어떤 변수를 사용할 지 주소값을 매번 지정해줘야 했음.
- 함수가 길어짐.
- 함수 내부에서도 포인터로 데이터를 다뤄야함.
-
함수의 이름을 항상 다르게 작성해야 한다.
- 전역 이름공간을 사용하기에 모든 함수마다 이름을 다르게 지어줘야 함.
-
프로그램을 확장하기 불편하다.
- 프로그램이 커질수록 기능구현 < 버그수정(유지보수).
- 절차지향은 프로그램에 수정 사항이 생기면 변경 사항이 많아짐 (필요한 함수를 명확하게 호출해야 하기 때문에).
- 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에서 나오는건 아님.)
-
가상 소멸자
- 업캐스팅 할 때, 객체의 소멸이 제대로 되지 않음.
- 가상 함수를 사용하여 가상 소멸자를 정의해주면, 제대로 인스턴스가 소멸함.
- 따라서 상위 클래스가 될 가능성이 있다면, 가상 소멸자를 정의해주어야함.
객체지향적 설계
- 메소드 : 기능.
- 필드 : 메소드의 상태, 기능 구현을 위한 데이터.
템플릿
-
함수
-
일반화 프로그래밍
- 타입에 관계없이 알고리즘을 기술하는 프로그래밍 패러다임
- cpp에서는 템플릿이라는 기능으로 일반화 프로그래밍을 지원함.
-
템플릿
관련문서