객체 지향 프로그래밍(Object-Oriented Programming, OOP)은 객체와 클래스를 기반으로 프로그램을 구성하는 프로그래밍 패러다임입니다. 상속, 다형성, 데이터 은닉과 같은 현실 세계의 개념을 소프트웨어 설계에 반영하며, 데이터와 그 데이터를 처리하는 함수를 하나의 단위로 묶어 외부의 무분별한 접근을 제한하는 것을 목표로 합니다.
객체 지향 프로그래밍의 핵심 개념
- 클래스(Class)
- 객체(Object)
- 캡슐화(Encapsulation)
- 다형성(Polymorphism)
- 상속(Inheritance)
- 추상화(Abstraction)
클래스(Class)
클래스는 데이터 멤버(변수)와 멤버 함수(메서드)를 자신의 구성 요소로 가지는 사용자 정의 데이터 타입입니다. 객체 지향 프로그래밍에서 클래스는 객체를 생성하기 위한 설계도 역할을 하며, C++에서 OOP를 이루는 가장 기본적인 빌딩 블록입니다. 클래스의 멤버에 접근하려면 해당 클래스의 인스턴스를 생성해야 합니다.
클래스의 주요 특징
클래스는 사용자 정의 데이터 타입입니다.
클래스는 데이터 멤버와 멤버 함수로 구성됩니다.
데이터 멤버는 클래스 내부에 선언되는 변수입니다.
멤버 함수는 데이터 멤버를 조작하는 메서드입니다.
데이터 멤버는 클래스의 속성(property)을, 멤버 함수는 클래스의 동작(behavior)을 정의합니다.
하나의 클래스로부터 여러 개의 객체를 생성할 수 있으며, 이 객체들은 모두 공통된 속성과 동작을 공유합니다.
문법
class class_name {
data_type data_name;
return_type method_name(parameters);
}
객체(Object)
객체는 클래스의 인스턴스(instance)입니다. 객체 지향 프로그래밍에서 실제로 사용되는 특성과 동작을 지닌 실체이며, 메모리가 할당되는 단위이기도 합니다. 클래스는 정의만으로는 메모리를 차지하지 않으며, 객체가 생성되는 시점에 비로소 메모리가 할당됩니다.
문법
class_name object_name;
예제 코드
아래는 두 숫자와 연산자를 받아 사칙연산을 수행하는 간단한 계산기 클래스 예제입니다.
#include<iostream>
using namespace std;
class calculator {
int number1;
int number2;
char symbol;
public :
void add() {
cout<<"두 수의 합은 "<<number1 + number2;
}
void subtract() {
cout<<"두 수의 차는 "<<number1 - number2;
}
void multiply() {
cout<<"두 수의 곱은 "<<number1 * number2;
}
void divide() {
cout<<"나눗셈 결과는 "<<number1 / number2;
}
calculator(int a, int b, char sym) {
number1 = a;
number2 = b;
symbol = sym;
switch(symbol){
case '+' : add();
break;
case '-' : subtract();
break;
case '*' : multiply();
break;
case '/' : divide();
break;
default : cout<<"잘못된 연산자";
}
}
};
int main() {
calculator c1(12, 34, '+');
}
실행 결과
두 수의 합은 46
캡슐화(Encapsulation)
캡슐화는 객체 지향 프로그래밍에서 데이터와 정보를 하나의 단위로 묶는 개념입니다. 형식적으로 정의하면, 캡슐화란 데이터와 그 데이터를 조작할 수 있는 관련 함수들을 하나로 결합하는 것을 의미합니다.
일상 속 예시를 통해 살펴보겠습니다. 대학에는 컴퓨터공학과, 정보통신학과, 전자공학과처럼 학과별 부서가 있습니다. 각 학과는 자체적인 학생 명단과 교육 과목을 관리하며, 수업 시간이나 학습 방법과 같은 고유한 규칙과 지침을 따릅니다. 각 학과를 하나의 클래스라고 생각해 보면, 학과는 해당 학과의 학생 정보와 교과목 데이터를 캡슐화하고 있고, 데이터를 다루는 방식(규칙·지침)도 함께 내포하고 있는 셈입니다. 이것이 바로 현실 세계에서의 캡슐화입니다.
캡슐화 덕분에 또 하나의 중요한 개념인 데이터 추상화(Data Abstraction), 즉 데이터 은닉(Data Hiding)이 가능해집니다. 캡슐화는 내부 데이터를 숨기고 외부에 필요한 정보만 노출하기 때문입니다.
다형성(Polymorphism)
다형성은 이름 그대로 '여러 형태'를 의미합니다. 즉, 객체 지향 프로그래밍에서 하나의 작업을 여러 형태로 수행할 수 있는 능력을 말하며, 메서드의 동작은 호출되는 상황이나 타입에 따라 달라집니다.
실생활 예시를 들어보겠습니다. 한 사람은 상황에 따라 집에서는 어머니이고, 직장에서는 관리자이며, 부모님께는 딸이기도 합니다. 같은 사람이라도 맥락에 따라 행동 방식이 달라지는 것처럼 말입니다. 다형성 개념은 바로 여기서 출발합니다.
C++에서는 다형성을 크게 두 가지 방식으로 구현합니다.
연산자 오버로딩(Operator Overloading) : 하나의 연산자가 사용되는 맥락에 따라 서로 다른 동작을 하도록 하는 기법입니다.
함수 오버로딩(Function Overloading) : 이름이 같은 함수가 매개변수의 개수나 타입 등 조건에 따라 여러 형태로 동작하도록 하는 기법입니다.
상속(Inheritance)
상속은 한 클래스가 다른 클래스의 속성이나 특징을 물려받을 수 있는 능력입니다. 이미 정의된 클래스의 메서드와 변수를 그대로 활용할 수 있게 해 주므로 코드 재사용성(reusability)을 높여주는 객체 지향 프로그래밍의 핵심 요소입니다. 속성을 물려주는 클래스를 기반 클래스(base class) 또는 부모 클래스(parent class)라 하고, 속성을 물려받는 클래스를 파생 클래스(derived class), 자식 클래스(child class) 또는 서브 클래스(subclass)라고 부릅니다.
C++는 다음과 같은 유형의 상속을 지원합니다.
- 단일 상속(Single Inheritance)
- 다중 상속(Multiple Inheritance)
- 다단계 상속(Multilevel Inheritance)
- 계층 상속(Hierarchical Inheritance)
- 혼합 상속(Hybrid Inheritance)
추상화(Abstraction)
데이터 추상화 또는 데이터 은닉은 불필요한 내부 구현을 숨기고 최종 사용자에게 꼭 필요한 정보만 보여주는 개념으로, 객체 지향 프로그래밍의 중요한 축입니다.
예를 들어 오토바이를 탈 때 우리는 브레이크를 잡으면 멈추고 스로틀을 돌리면 가속된다는 사실만 알면 됩니다. 내부 엔진이 어떻게 작동하는지 몰라도 되고, 굳이 알 필요도 없습니다. 이처럼 사용자에게 필요한 기능만 노출하고 복잡한 내부 동작은 감추는 것이 바로 데이터 추상화입니다.
C++에서는 다음 두 가지 방법으로 데이터 추상화를 구현할 수 있습니다.
- 클래스(class) 활용
- 헤더 파일(header file) 활용