객체지향 프로그래밍 개념
절차지향과 객체지향
- 절차지향 프로그래밍 방식은 데이터와 프로세스를 별도의 모듈에 위치시키는 프로그래밍 방식이다.
- 데이터와 프로세스를 별도의 모듈에 위치시킴으로 인해서 생기는 문제
- 함수(프로세스)가 데이터에 너무 의존적인 방식이기 때문에 데이터 구조가 변경될 시 함수의 수정이 필요하고, 이로 인한 변경의 영향을 지역적으로 고립시키기가 어렵다.
- 프로그램 확장과 수정이 어려운 구조이다.
- 현실 세계의 비즈니스 모델과 괴리가 발생하는, 즉 우리의 직관에 위배되는 프로그램 구조를 갖게 된다. 즉, 이해하기 어렵다.
- 절차지향 프로그래밍 방식의 문제점들을 개선하기 위해 객체지향 프로그래밍 방식이 도입됐다.
- 객체지향 프로그래밍 방식은 데이터와 프로세스를 동일한 모듈 내부에 위치시키는 프로그래밍 방식이다.
- 객체지향 프로그래밍 방식의 장점
- 프로세스가 데이터에 의존적이지 않기 때문에 프로그램 확장과 변경에 유리하다.
- 현실 세계의 비즈니스 모델을 우리의 직관에 맞게 프로그램에도 표현해낼 수 있다. 즉, 이해하기가 편리한 구조이다.
- 객체지향 프로그래밍을 위해 데이터와 프로세스를 동일한 모듈 내부에 위치시키는데, 이 때 모듈에 해당하는 것이 객체이다. 객체는 객체지향 프로그래밍의 가장 기본적 개념이 된다.
객체
- 객체는 실세계의 문제 영역에 존재하는 대상물을 그 대상물의 속성과 메서드로 모델링한 것이다.
- 속성: 객체의 상태를 나타내는 데이터
- 메서드: 내부의 데이터를 사용하여 정해진 동작을 하는 함수
- 객체지향 방식에서는 관련된 데이터와 함수들이 하나로 묶여 객체로 표현
메시지
- 프로그램이 필요한 기능을 해내기 위해서는 객체들이 상호작용해야만 한다.
- 한 객체가 다른 객체의 기능을 필요로 한다면 그 객체는 상대방 객체에게 필요한 작업이 이루어지도록 요구한다. 이를 객체지향 프로그래밍 방식에서는 메시지를 보낸다고 한다.
- 메시지를 보내기 위해서는 해당 메시지를 수신할 수신 객체를 정하고, 그 메시지를 처리할 수신 객체의 메서드를 호출해야 한다. 이 과정에서 전달해야 할 데이터가 있다면 함수의 인수를 통해 전달한다.
클래스
- 클래스에는 객체가 포함할 속성과 메서드들에 대한 명세가 정의되어 있다.
- 클래스를 이용하여 동일한 속성 및 메서드를 갖는 객체들을 생성한다.
- 객체는 클래스의 사례(instance)라고 부르기도 한다.
- 캡슐화
- 캡슐화는 객체의 사용자 측면의 사항과 설계자 측면의 사항을 분리하는 것이다.
- 캡슐화는 객체 내부의 구현에 대한 사항은 감추고, 외부로는 공개된 메서드를 통해 인터페이스를 제공하여 객체를 사용할 수 있게 하는 것을 의미한다.
- 캡슐화된 객체 내부의 세부 사항을 사용자가 직접 사용할 수 없도록 감추는데, 이를 정보 은닉이라고 한다.
- 캡슐화를 위해 공개할 멤버와 공개하지 않을 멤버를 구분할 수 있다.
상속
- 유사한 유형의 클래스가 여러 개 있을 경우 이 클래스들에는 공통적인 내용과 각 클래스 별로 고유한 내용을 갖게 된다.
- 클래스들의 공통적인 사항을 포함하는 클래스를 만들고, 개별 클래스들은 이를 공유하면서 각자에 고유한 사항만 포함하도록 설계할 수 있다.
- 이러한 방식으로 설계된 클래스들은 계층적인 관계를 갖게 된다.
- 상위 클래스의 속성 및 메소드를 하위 클래스가 이어받는 것을 상속이라고 부른다.
- 상위 클래스 : 기초 클래스, 슈퍼 클래스, 부모 클래스
- 하위 클래스 : 유도 클래스, 서브 클래스, 파생 클래스
클래스 선언과 객체 정의
- 클래스는 C++ 언어에서 객체지향 개념을 구현하기 위한 도구이다.
- 클래스 안에 정의한 속성들을 데이터 멤버라고 부르고, 메서드를 멤버 함수라고 부른다.
클래스 선언
class ClassName {
가시성_지시어_1:
데이터 멤버 또는 멤버함수 리스트;
가시성_지시어_2:
데이터 멤버 또는 멤버함수 리스트;
}
가시성 지시어와 공개 영역
- 가시성 지시어는 그 다음에 나열되는 데이터 멤버나 멤버함수들이 외부에 공개되는 범위를 나타낸다.
- 지정된 가시성은 다음 지시어가 나올 때까지 유효하다.
- 가시성 지시어 뒤에는 클래스의 데이터 멤버 및 멤버 함수들이 나열된다.
| 가시성 지시어 |
공개되는 범위 |
| private |
1. 소속 클래스의 멤버 함수 2. 친구 클래스(friend class)의 멤버 함수 및 친구 함수(friend function) |
| protected |
1. 소속 클래스의 멤버 함수 2. 유도 클래스의 멤버 함수 |
| public |
1. 전 범위 |
데이터 멤버의 선언
- 데이터 멤버는 일반적으로 private 멤버로 선언한다.
- 객체의 모델링은 객체의 행위를 중심으로 이루어지며, 데이터 멤버는 그러한 행위와 관련된 객체 내부의 상태로 보는 것이 일반적 => 주로 private
- 멤버함수의 선언
- 멤버함수는 클래스 선언문 내에 선언하거나, 클래스 선언문에는 멤버함수의 원형만 선언해놓고 외부에 별도로 멤버함수를 정의한다.
- 객체를 사용하기 위한 인터페이스로 클래스 외부에 제공하기 위한 멤버 함수는 public으로 가시성을 지정하여 어느 위치에서든 자유롭게 사용할 수 있도록 한다.
객체의 정의 및 사용
- 실제 객체는 일반 자료형의 변수를 정의하듯 별도로 정의하여야 한다.
- 객체를 정의한다는 것은 실제 객체를 만드는 것을 의미한다.
- 객체를 정의하는 기본적인 형식
ClassName objName;
ClassName objName1, objName2, ...;
```
// Counter.hpp
#ifndef COUNTER_H_INCLUDED
#define COUNTER_H_INCLUDED
class Counter {
private
int value;
public:
Counter(int value);
void reset();
void count();
int getValue() const;
}
#endif
```
* `Counter` 클래스 구현 파일(`Counter.cpp`)
```
// Counter.cpp
#include "Counter.hpp"
Counter::Counter(int value)
{
this.value = value;
}
void Counter::reset()
{
value = 0;
}
void Counter::count()
{
++value;
}
int Counter::getValue() const
{
return value;
}
```
* `Counter` 객체 정의와 사용(`CntMain.cpp`)
```
// CntMain.cpp
#include <iostream>
#include "Counter.hpp"
using namespace std;
int main(){
Counter cnt; // Counter 객체 정의
cnt.reset();
cout << "계수기의 현재 값: " << cnt.getValue() << endl;
cnt.count();
cnt.count();
cout << "계수기의 현재 값: " << cnt.getValue() << endl;
return 0;
} // Counter 객체 소멸
```
const 멤버함수
- Counter 클래스의 getValue 메소드에는 const 키워드가 붙어있다.
- const 키워드가 붙은 멤버함수, 즉 const 멤버함수를 정의하는 것은 그 함수가 데이터 멤버를 변경하지 않는다는 것을 명시적으로 보여주는 문서화의 의미가 있다.
- const 객체를 정의하였다면 그 객체에 대해서는 const 멤버함수만 사용할 수 있다.
const Counter c; // const Counter 객체 정의, 상수 객체
int n = c.getValue(); // OK
c.count() // ERROR - count 메서드는 const 멤버함수가 아니다.