- 해당 글은 UNSEEN 2기 코딩 테스트를 대비하여 정리 목적으로 적은 글입니다. 잘못된 부분이 있다면 지적해주시면 감사하겠습니다.
1. 객체지향 프로그래밍의 특징
객체지향 프로그래밍이란?
객체 지향 프로그래밍(Object-Oriented Programming, OOP)은 컴퓨터 프로그램을 명령어의 목록으로 보는 시각에서 벗어나 여러 개의 독립된 단위, 즉 객체들의 모임으로 파악하고자 하는 것을 말한다.
자동차를 만들 때 작은 부품을 먼저 만들고, 이렇게 만든 부품을 하듯이, 객체지향적으로 프로그램을 설계한다는 말의 의미는 객체를 만들고 이를 조립해서 하나의 거대한 프로그램을 만든다는 뜻이다.
C언어 이후, 많은 객체지향 언어가 나타났는데 대표적인 것이 Objective-C, C++, Java, C#, Python, 루비, 스위프트 등이 있다.
객체지향 프로그래밍의 장점
객체지향적으로 프로그램을 설계하기 시작하면서 개발자들은 더 큰 소프트웨어를 개발할 수 있게 되었다. 객체지향 프로그래밍의 장점은 다음과 같다.
- 프로그램을 보다 유연하고 변경이 용이하게 만들 수 있다.
- 각각의 부품이 독립적인 역할을 갖기 때문에 코드의 변경을 최소화하고 유지보수하는 데 유리하다.
- 코드의 재사용을 통해 반복적인 코드를 최소화하고 코드를 간결하게 표현할 수 있다.
- 인간이 세상을 바라보는 관점을 도입했기 때문에 이전보다 인간 친화적이고 직관적인 코드를 작성하기에 용이하다.
객체지향 프로그래밍의 특징에는 추상화, 상속, 다형성, 캡슐화가 있다.
객체(object)란?
객체지향 프로그래밍은 객체로부터 시작된다. 객체지향 개념의 전제는 실제 세계가 객체로 구성되어 있고 눈에 보이는 모든 현상은 객체들 간의 상호작용을 통해 발생한다는 것이다.
객체지향 프로그래밍은 책상, 의자, 책, 사람, 학교 등 ‘모든 실재하는 대상’을 객체라 부른다. 이때, 객체는 눈에 보이는 것뿐만 아니라 사상과 추상적인 개념 같이 사람이 말로 표현가능한 모든 것을 객체라 하는 것이다.
객체지향 프로그래밍에서는 객체를 추상화시켜 속성(state)과 기능(behavior)으로 분류하고, 이를 변수(variable)와 함수(function)로 정의한다.
객체지향 프로그래밍의 특징
1. 추상화(Abstraction)
추상: 여러 가지 사물이나 개념에서 공통되는 특성이나 속성 따위를 추출하여 파악하는 작용.(네이버 국어사전)
객체지향 프로그래밍에서 추상화란 객체의 공통적인 속성과 기능을 추출하여 정의하는 것을 의미한다.
예를 들어 자동차
와 오토바이
는 모두 이동수단
이며 공통적으로 앞으로 가기, 뒤로 가기라는 기능을 갖고 있다. 이를 이용하면 자동차
와 오토바이
는 하위 클래스의 공통적인 기능(전진, 후진)을 추출하여 이동수단
이라는 상위 클래스에 정의할 수 있다.
추상화를 구현하기 위해 추상 클래스, 인터페이스라는 문법을 사용한다.
- 추상 클래스: 몇몇 함수를 구현하지 않은 클래스. Java에서는 클래스에 abstract 키워드를 붙이면 되고, C++에서는 virtual 키워드로 된 함수를 아래와 같이 하나 이상 구현하지 않으면 된다.
- 인터페이스: 모든 함수가 구현되지 않은 클래스. 즉, 구현된 함수가 하나도 없어서 껍데기만 있는 클래스이다. Java에서는 interface 키워드로 만들 수 있고, C++는 기본적으로 인터페이스를 지원하지 않는다.
#include <iostream>
// 부모 클래스: 이동수단 클래스
class Vehicle
{
public:
virtual void moveForward() = 0;
virtual void moveBackward() = 0;
}
// 자식 클래스: 자동차 클래스
class Car : Vehicle
{
public:
void moveForward()
{
std::cout << "차가 앞으로 전진합니다";
}
void moveBackward()
{
std::cout << "차가 뒤로 후진합니다";
}
}
// 자식 클래스: 오토바이 클래스
class MotorBike : Vehicle
{
public:
void moveForward()
{
std::cout << "오토바이가 앞으로 전진합니다";
}
void moveBackward()
{
std::cout << "오토바이가 뒤로 후진합니다";
}
}
위 코드에서는 Vehicle 인터페이스를 Car, MotorBike 클래스에서 각각의 클래스의 맥락에 맞게 구현하고 있다.
객체지향 프로그래밍에서는 보다 유연하고 변경에 열려있는 프로그램을 설계하기 위해, 위와 같이 역할과 구현을 분리한다. Vehicle 클래스가 어떤 역할을 해야 하는지를 보여준다면, Car와 MotorBike 클래스에서 이를 구현하는 것이다.
2. 상속(Inheritance)
상속이란 기존 클래스를 재활용하여 새로운 클래스를 작성하는 문법이다.
즉, 새로운 클래스가 기존의 클래스의 자료와 연산을 이용할 수 있는 것이다.
상속은 클래스 간에 공유될 수 있는 속성과 기능을 상위 클래스로 추상화시키고, 해당 상위 클래스에서 확장된 하위클래스들이 상위 클래스의 속성과 기능을 간편하게 사용할 수 있게 한다.
상위 클래스에서 한 번만 속성과 기능을 정의해두면 코드를 재사용할 수 있게 되어 반복적인 코드를 최소화하고 공유하는 속성과 기능에 간편하게 접근할 수 있게 된다.
자동차와 오토바이 클래스에서 따로 기능을 구현한다면 아래와 같이 model
, color
, wheels
같은 속성과 moveForward()
, moveBackward()
가 반복된다.
#include <iostream>
// 자동차 클래스
class Car
{
public:
string model;
string color;
int wheels;
// Car 클래스 고유 속성
bool isConvertible;
void moveForward()
{
std::cout << "앞으로 전진합니다";
}
void moveBackward()
{
std::cout << "뒤로 후진합니다";
}
void openWindow()
{
std::cout << "창문이 열립니다";
}
}
// 오토바이 클래스
class MotorBike
{
public:
string model;
string color;
int wheels;
// MotorBike 클래스 고유 속성
bool isRaceable;
void moveForward()
{
std::cout << "앞으로 전진합니다";
}
void moveBackward()
{
std::cout << "뒤로 후진합니다";
}
// MotorBike 클래스 고유 기능
void Stunt()
{
std::cout << "묘기를 부립니다.";
}
}
여기서 공통되는 부분을 Vehicle 클래스로 묶으면 다음과 같이 된다.
#include <iostream>
// 상위 클래스: 이동수단 클래스
class Vehicle
{
public:
string model;
string color;
int wheels;
void moveForward()
{
std::cout << "앞으로 전진합니다";
}
void moveBackward()
{
std::cout << "뒤로 후진합니다";
}
}
// 자동차 클래스
class Car : Vehicle
{
public:
bool isConvertible;
void openWindow()
{
std::cout << "창문이 열립니다";
}
}
// 오토바이 클래스
class MotorBike : Vehicle
{
public:
bool isRaceable;
void Stunt()
{
std::cout << "묘기를 부립니다.";
}
}
위 코드를 보면 Car와 MotorBike 클래스의 공통된 속성과 기능을 상위 클래스인 Vehicle 클래스에 정의하고, 하위 클래스인 Car와 MotorBike 가 이를 상속받도록 정의했다. 이렇게 하면 상위 클래스 Vehicle의 기능 부분을 재사용하므로 하위 클래스에서 코드를 반복하여 작성하지 않아도 된다.
3. 다형성(Polymorphism)
다형성이란 하나의 개념이 여러 가지 형태로 변할 수 있는 성질을 말한다. 객체지향에서의 다형성은 ‘프로그램 언어의 각 요소가 그 맥락에 따라 다른 역할을 수행할 수 있는 객체 지향의 특성’을 말한다.
예를 들어 살펴보자.
class Vehicle
{
public:
virtual void moveForward()
{
std::cout << "앞으로 갑니다";
}
}
class Car : Vehicle
{
public:
void moveForward()
{
std::cout << "자동차가 앞으로 갑니다";
}
}
위 코드에서는 moveForward
메서드가 두 함수에서 다르게 동작한다. 상위 클래스 Vehicle
에서는 “앞으로 갑니다”라고만 나오지만 하위 클래스 Car
에서는 “자동차가 앞으로 갑니다”라고 다르게 나타난다. 이를 메서드 오버라이딩(overriding)이라 한다.
Java에서는 꼭 virtual 키워드를 써줄 필요는 없지만, C++에서는 동적 바인딩이라는 개념을 적용하기 위해 virtual 키워드를 붙여줘야 Car를 Vehicle로 변환했을 때 기능이 달라지는 문제가 없다. 혹시나 궁금하다면 C++ 동적 바인딩을 찾아보자.
class Human
{
void Drink(Water water)
{
std::cout << "물을 마십니다";
}
void Drink(Soda soda)
{
std::cout << "탄산음료를 마십니다";
}
}
음료수를 마시는 경우에도, 같은 Drink
함수이지만 물을 마시는 경우의 함수가 있을 수 있고 탄산음료를 마시는 경우일 수도 있다. 이렇게 같은 클래스 내에서 같은 이름의 메서드를 여러 개 중복해서 정의하는 것을 메서드 오버로딩(overloading)이라 한다.
앞에서 알아본 것처럼 객체 지향 언어에서는 같은 이름의 메서드가 상황에 따라 다른 역할을 수행할 수 있는데, 이것들은 다형성의 일종이다.
보다 정확한 다형성의 정의는 다음과 같다.
객체 지향 프로그래밍에서 다형성이란 한 타입의 참조변수를 통해 여러 타입의 객체를 참조할 수 있도록 만든 것을 의미합니다. 좀 더 구체적으로, 상위 클래스 타입의 참조변수로 하위 클래스의 객체를 참조할 수 있도록 하는 것입니다.
예를 들면, 앞에서는 이동수단
에는 자동차
나 오토바이
가 있다고 정의했다. 다르게 말하면 자동차
나 오토바이
나 모두 이동수단
으로 묶을 수 있다. 이동수단
처럼 넓은 개념, 즉 상위 클래스 타입의 변수로 하위 클래스를 참조할 수 있는 것이다.
int main()
{
Vehicle* vehicles[2];
vehicles[0] = new Car();
vehicles[1] = new MotorBike();
for (int i = 0; i < 2; i++)
{
// 두 클래스 모두 동일한 방식으로 다룰 수 있게 된다.
vehicle[i]->moveForward();
}
delete vehicles[0];
delete vehicles[1];
}
다형성이라는 특징 덕분에 여러 종류의 객체를 하나의 배열로 다룰 수도 있다.
4. 캡슐화(Encapsulation)
캡슐화란 서로 연관있는 속성과 기능을 하나의 캡슐로 만들어 외부로부터 보호하는 것을 말한다.
- 데이터 보호(data protection) - 외부로부터 클래스에 정의된 속성과 기능을 보호한다.
- 데이터 은닉(data hiding) - 내부의 동작을 감추고 외부에는 필요한 부분만 노출시킨다.
이를 달성하기 위해 접근 제한자를 사용하거나 getter/setter
메서드를 사용할 수 있다.
접근 제한자(access modifiers)는 클래스나 멤버들을 외부에서 접근하지 못하도록 접근을 제한하는 역할을 한다.
class Car
{
public:
void operate()
{
startEngine();
moveForward();
openWindow();
}
private:
void startEngine() { ... }
void moveForward() { ... }
void openWindow() { ... }
}
C++에는 접근 제한자로 public, protected, private이 있다.
위에서 보면 operate 함수는 public으로 묶여 외부 클래스에서도 접근할 수 있다.
하지만 startEngine, moveForward, openWindow는 private로 묶여 있는데, private 키워드는 오직 자기 클래스, 즉 Car에서만 해당 메서드에 접근할 수 있도록 제한하고 있다. 이렇게 굳이 다른 클래스에서 접근할 필요가 없거나 접근하면 안되는 함수는 접근을 제한하는 것이다.
이렇게 되면 외부 클래스에서는 operate 함수만을 호출할 수 있게 된다.
또, getter/setter
를 이용하면 원하는 속성만 가져오거나 변경할 수도 있게 제약을 걸 수 있다.
class Player
{
private:
string nickname;
int level;
int userId;
public:
string getNickname() { return nickname; }
void setNickName(string newName) { nickname = newName; }
public:
string getLevel() { return level; }
void setLevel(int newLevel) { level = newLevel; }
public:
int getUserId() { return userId; }
private:
void setUserId(int newId) { userId = newId; }
}
위 코드에서 Player 클래스는 유저 id, 닉네임, 레벨 속성을 갖는데 모든 속성값이 private 접근 제한자로 선언되어 있다. 이때 위와 같이, getNickname()
, setNickName()
와 같이 getter/setter
를 만들고 필요한 접근제한자만을 외부에 열어놓을 수 있다. nickname
, level
은 getter/setter
모두 열려 있지만 userId
는 getter
만 열려 있다.
출처
객체 지향 프로그래밍의 4가지 특징ㅣ추상화, 상속, 다형성, 캡슐화 - (codestates.com)
객체 지향 프로그래밍의 4가지 특징ㅣ추상화, 상속, 다형성, 캡슐화 -
객체 지향 프로그래밍은 객체의 유기적인 협력과 결합으로 파악하고자 하는 컴퓨터 프로그래밍의 패러다임을 의미합니다. 객체 지향 프로그래밍의 기본적인 개념과 그 설계를 바르게 하기 위
www.codestates.com
객체 지향 프로그래밍 - 위키백과, 우리 모두의 백과사전 (wikipedia.org)
객체 지향 프로그래밍 - 위키백과, 우리 모두의 백과사전
위키백과, 우리 모두의 백과사전. 객체 지향 프로그래밍(영어: Object-Oriented Programming, OOP)은 컴퓨터 프로그래밍의 패러다임 중 하나이다. 객체 지향 프로그래밍은 컴퓨터 프로그램을 명령어의 목
ko.wikipedia.org
다형성 (컴퓨터 과학) - 위키백과, 우리 모두의 백과사전 (wikipedia.org)
다형성 (컴퓨터 과학) - 위키백과, 우리 모두의 백과사전
위키백과, 우리 모두의 백과사전. 프로그램 언어의 다형성(多形性, polymorphism; 폴리모피즘)은 그 프로그래밍 언어의 자료형 체계의 성질을 나타내는 것으로, 프로그램 언어의 각 요소들(상수, 변
ko.wikipedia.org
'UNSEEN' 카테고리의 다른 글
UNSEEN 5. 게임 알고리즘 (1): A*, 쿼드트리 (0) | 2024.01.30 |
---|---|
UNSEEN 대비 4. C++ 주요 컨테이너 (2) (map, unordered_map) (1) | 2024.01.28 |
UNSEEN 대비 4. C++ 주요 컨테이너 (1) (array, vector, list) (1) | 2024.01.28 |
UNSEEN 대비 3. 메모리 영역 (1) | 2024.01.25 |
UNSEEN 대비 2. C++ 언어의 특징 (0) | 2024.01.25 |
댓글