컴퓨터 프로그램을 어떤 데이터를 입력받아 순서대로 처리하고 결과를 도출하는 명령어들의 목록으로 보는 시각에서 벗어나 여러 독립적인 부품들의 조합, 즉 객체들의 유기적인 협력과 결합으로 파악하고자 하는 컴퓨터 프로그래밍의 패러다임을 의미.
어떤 프로그램의 일부에 해당하는 작은 부품, 즉 객체를 먼저 만들고 이렇게 만들어진 여러 가지 객체들을 조립해서 하나의 완성된 프로그램을 만드는 프로그래밍 방법론을 뜻한다.
1) 프로그램을 보다 유연하고 변경이 용이하게 만들 수 있다.
2) 코드의 변경을 최소화하고 유지보수를 하는 데에 유리하다.
3) 인간 친화적이고 직관적인 코드를 작성하기에 용이하다.
4) 코드의 재사용을 통해 반복적인 코드를 최소화하고, 코드를 최대한 간결하게 표현할 수 있다.
객체 지향 프로그래밍의 가장 기본적인 단위이자 시작점. 실제 세계는 객체들로 구성되어 있으며, 보이는 모든 현상과 발생하는 모든 사건은 객체들간의 상호작용을 통해 발생한다는 생각에서 객체 지향 프로그래밍이 시작된다.
객체 지향 프로그래밍에서는 각각의 객체를 추상화시켜 속성과 기능으로 분류한 후에, 이를 다시 변수와 함수로 정의한다. (속성 –> 변수 / 기능 –> 함수)
: 객체의 공통적인 속성과 기능을 추출하여 정의하는 것
자동차와 오토바이를 예시로 들면, 둘은 모두 이동 수단이며, 전진과 후진을 할 수 있다는 공통점을 가진다. 여기서 자동차와 오토바이라는 하위 클래스들의 공통적인 기능(전진, 후진)을 추출하여 이동 수단이라는 상위 클래스에 정의할 수 있다.
추상화를 구현할 수 있는 문법 요소로는 추상 클래스와 인터페이스가 있다.
class Vehicle // 부모 클래스
{
public :
virtual void moveForward() = 0;
virtual void moveBackward() = 0;
}
class Car : public Vehicle // 자식 클래스 1
{
public :
void moveForward() override { cout << "앞으로 이동 " };
void moveBackward() override { cout << "뒤로 이동 " };
}
class MotorCycle : public Vehicle // 자식 클래스 2
{
public :
void moveForward() override { cout << "앞으로 이동 " };
void moveBackward() override { cout << "뒤로 이동 " };
}
interface IVehicle // 인터페이스
{
public :
virtual void moveForward() = 0;
virtual void moveBackward() = 0;
}
class Car : public IVehicle // 자식 클래스 1
{
public :
void moveForward() override { cout << "앞으로 이동 " };
void moveBackward() override { cout << "뒤로 이동 " };
}
class MotorCycle : public IVehicle // 자식 클래스 2
{
public :
void moveForward() override { cout << "앞으로 이동 " };
void moveBackward() override { cout << "뒤로 이동 " };
}
: 기존 클래스를 재활용하여 새로운 클래스를 작성하는 것
상속은 클래스 간 공유될 수 있는 속성과 기능들을 상위 클래스로 추상화 시켜 해당 상위 클래스로부터 확장된 여러 개의 하위 클래스들이 모두 상위 클래스의 속성과 기능들을 간편하게 사용할 수 있도록 한다.
즉, 클래스들 간 공유하는 속성과 기능을 반복적으로 정의할 필요 없이 한 번만 정의 해두고 간편하게 재사용할 수 있어 반복적인 코드를 최소화하고 공유하는 속성과 기능에 간편하게 접근해 사용 가능하다.
class Vehicle // 부모 클래스
{
public :
void moveForward() { cout << "앞으로 이동 "; }
void moveBackward() { cout << "뒤로 이동 "; }
private :
double fuel;
string color;
}
class Car : public Vehicle // 자식 클래스 1
{
public :
void openWindow() { cout << "창문 열기"; }
void moveForward() override { cout << "차가 앞으로 이동 "; }
}
class MotorCycle : public Vehicle // 자식 클래스 2
{
public :
void moveForward() override { cout << " 오토바이가 앞으로 이동 "; }
}
상위 클래스를 상속받는 하위 클래스들은 속성과 기능들을 그대로 받아서 사용하거나, 선택적으로 오버라이딩으로 재정의하여 사용할 수도 있다.
: 어떤 객체의 속성이나 기능이 그 맥락에 따라 다른 역할을 수행할 수 있는 특성
대표적인 예로 메서드 오버라이딩과 메서드 오버로딩이 있다.
class Vehicle
{
public :
void moveForward() { cout << "앞으로 이동 "; }
void moveBackward() { cout << "뒤로 이동 "; }
}
class Car : public Vehicle
{
public :
void moveForward() override { cout << "차가 앞으로 이동 "; }
void moveBackward() override { cout << "차가 뒤로 이동 "; }
}
위 코드처럼 같은 이름의 moveForward()
와 moveBackward()
가 각각의 클래스에서의 재정의(오버라이딩)에 의해 다른 역할을 수행하게 된다.
하나의 클래스 내에서 같은 이름의 메서드를 여러 개 중복하여 정의하는 메서드 오버로딩도 같은 맥락에서 다형성을 가진다고 할 수 있다.
class Calculator
{
public :
int add (int x, int y) { return x + y; }
double add (double x, double y) { return x + y; }
}
위 코드처럼 같은 이름의 add
라는 함수지만 인수로 전달되는 변수들의 자료형에 따라 반환하는 자료형도 다르게 작동하는 함수를 중복 정의할 수 있다.
: 클래스 안에 서로 연관있는 속성과 기능들을 하나의 캡슐로 만들어 데이터를 외부로부터 보호하는 것
캡슐화를 구현하기 위해서는 접근 제한자를 사용할 수 있다.
class TestClass
{
private :
int importantValue;
public :
int getValue(int value)
return this->importantValue;
void setValue(int value)
this->importantValue = value;
}
TestClass
클래스의 importantValue
라는 변수는 private 제한자로 정의되어 있기 때문에 해당 변수에 직접 접근할 수 없고, getValue()
와 setValue()
함수를 통해서만 참조 및 수정이 가능하다.
👁️🗨️ 참고
https://www.codestates.com/blog/content/객체-지향-프로그래밍-특징