개요
C++을 공부하는 과정에서 객체지향을 접하게 되었다. 단어 그대로 해석해보면 객체를 활용하는 방식으로 프로그래밍을 하라는 의미인 것 같은데, 객체가 무엇인지 ! 객체를 활용하는 방법이 무엇인지 ! 한 번 알아보고자 정리하게 되었다.
1. 객체
객체는 실세계의 사물이나 개념을 프로그래밍적으로 모델링한 것이다. 객체는 상태(state)와 행동(behavior)을 가진다. 상태는 객체가 가지고 있는 데이터를 의미하며 속성, 필드로 정의되고, 행동은 이러 데이터를 다루는 메소드를 통
해 이루어진다.
2. 객체지향 프로그래밍
소프트웨어 개발의 한 접근 방식으로, 프로그램을 "객체"라는 독립적인 단위로 나누어 설계하고 개발하는 방법론이다.
객체지향과 함께 회자되는 절차지향이라는 개념도 있으니 둘의 차이점을 알아두자.
3. 객체지향의 특징 4가지
1. 상속
객체는 클래스를 기반으로 생성되며, 한 클래스는 다른 클래스를 상속하여 기존의 기능을 확장할 수 있다.
→ 코드중복을 줄이고 계층적인 구조를 형성할 수 있다.
ex) 자동차, 오토바이, 버스 클래스는 차량이라는 클래스를 상속받아서, 차량의 시동걸기( ) 메소드를 확장 구현할 수 있다.
2. 추상화
객체가 제공하는 기능에 대한 구체적인 세부사항을 숨기고 중요한 부분만 노출시키는 개념이다.
→ 인터페이스를 통해 구현하므로 세부구현을 교체하거나 확장하기 용이하다.
ex) 자동차 클래스의 주행( ) 메소드는 자동차 내부에서 어떻게 동작하는지에 대한 세부사항을 숨기고, 외부에서는 호출만 가능하게 구현한다.
3. 다형성
같은 이름의 메소드가 다른 방식으로 동작하는 특성을 의미한다.
→ 코드의 재사용성을 높여 중복코드를 방지한다.
ex) 주행( ) 메소드는 자동차, 오토바이, 버스 객체에 대해 다르게 구현될 수 있다.
4. 캡슐화
객체의 상태를 보호하고 외부에서 직접 접근하지 못하게 하는 개념이다.
→ 정보은닉을 통해 데이터의 무결성을 보장하고, 유지보수성을 높인.
ex) 자동차 클래스의 speed 변수 값의 수정은 setSpeed( )와 같은 메소드를 통해서만 가능하다.
4. 객체지향의 5대 원칙
SOLID 원칙
1. S (SRP : Single Responsibility Principle 단일책임원칙)
: 클래스는 단 하나의 책임만을 가져야 한다.
의도 : 각 클래스가 특정 기능만 수행하도록 설계하여 코드의 응집도를 높이고, 변경 시 영향을 최소화 할 수 있다.
![]() |
↓
![]() |
Student 클래스에는 학생에 관한 정보만 있는 것이 최선이다. calculateGrade를 Student 클래스에 구현하는 경우, 버그가 발생했을 때 이게 학생에 대한 로직을 처리하다가 발생한 것인지, 성적 관련 로직을 처리하다가 발생한 것인지 명확히 구분하기가 힘들어진다. 따라서, 클래스에 하나의 책임만을 할당하여 코드의 가독성과 유지보수성을 높이는 것이 중요하다.
2. O (OCP : Open/Closed Principle 개방-폐쇄 원칙)
: 확장에는 열려 있어야 하고, 수정에는 닫혀 있어야 한다.
의도 : 기존 코드를 건드리지 않고 새로운 기능을 추가할 수 있도록 하여 변경으로 인한 버그 발생을 최소화 한다.
![]() |
↓
![]() |
ShapeManager에서 drawShape를 구현할 때, Circle이나 Square뿐만 아니라 새로운 도형이 추가되면 해당 도형에 적합한 로직을 추가해야 한다. 이를 switch문으로 구현하면 case가 하나씩 늘어나고, if문으로 구현하면 else if가 추가될 것이다. 이런 방식은 조건문이 복잡해지고, 다른 조건에 영향을 줄 가능성을 높인다. 따라서 응집도를 높이고 결합도를 낮추기 위해 Shape라는 인터페이스를 정의하고 각 도형이 이를 구현하도록 설계하는 것이 좋다. 이렇게 하면 서로 간섭 없이 새로운 도형을 쉽게 추가하고 관리할 수 있다.
3. L (LSP : Liskov Substitution Principle 리스코프 치환 원칙)
: 하위 클래스는 상위 클래스와 대체 가능해야 한다.
의도 : 상속 관계에서 코드의 일관성을 유지하고, 예상치 못한 동작을 방지한다.
![]() |
↓
![]() |
Square 클래스가 Rectangle을 상속받게 되는 경우 정사각형임에도 가로, 세로의 길이를 각각 지정해주어야 한다. 한 변의 길이만 지정해주면 되는 정사각형의 경우 비효율적이고, 정상적으로 넓이 계산이 이루어지지 않을 수도 있다. 불필요한 메서드는 제거하고, Square = ?, Rectangle = ?라고 가정을 했을 때 ? 부분에 넣어도 어색하지 않은 인터페이스를 정의하여 상속받도록 구현하는 것이 유지보수에 유리하다.
4. I (ISP : Interface Segregation Principle 인터페이스 분리 원칙)
: 클라이언트는 자신이 사용하지 않는 메서드에 의존하지 않아야 한다.
의도 : 불필요한 의존성을 제거하여 코드의 응집도를 높이고 변경 영향을 최소화 한다.
![]() |
↓
![]() |
Machine 인터페이스에 print( )와 scan( )을 정의하게 되는 경우 프린터에서는 불필요하게 스캔 메서드를 구현해야하고, 반대로 스캐너에서는 필요없는 프린트 메서드를 구현해야 한다. 이는 불필요한 의존성이 발생하는 것이므로 관련없는 인터페이스는 독립적으로 구현하는 것이 좋다.
5. D (DIP : Dependency Inversion Principle 의존 역전 원칙)
: 고수준 모듈은 저수준 모듈에 의존해서는 안 된다. 둘 다 추상화에 의존해야 한다.
의도 : 모듈 간 결합도를 낮추고, 변경에 용이하도록 한다.
![]() |
↓
![]() |
Computer 클래스가 Keyboard, Monitor 클래스와 직접적인 연관성을 가지는 경우, 새로운 키보드나 모니터가 추가가 되었을 때에도 컴퓨터와 높은 결합도를 가지게 될 것이다. 결합도가 높아지면, 하나의 클래스를 수정할 때 다른 클래스에 영향을 줄 수 있으므로 결합도를 최소화하는 방향으로 구현해야 한다. 따라서, 각각의 키보드는InputDevice를 각각의 모니터는 OutputDevice를 상속받는 형태로 관리하는 것이 유지보수에 용이하다.
느낀 점
객체와 객체지향을 이해하는 과정에서 4가지 특징과 5대 원칙에 대해 알게 되었다. 4가지 특징 중 추상화와 캡슐화의 차이가 명확히 와닿지 않았는데, 간단히 생각하면 인터페이스를 활용하는 것이 추상화, Getter와 Setter를 사용하는 것이 캡슐화라고 볼 수 있을 것 같다.
5대 원칙은 다소 반복되는 내용처럼 느껴졌는데, 특히 OCP(개방-폐쇄 원칙)와 SRP(단일 책임 원칙)를 잘 준수하면 나머지 원칙들도 자연스럽게 충족될 것 같은 인상이었다.
객체지향에 대해 알아봤으니 이젠 절차지향이 뭔지 알아봐야겠다.
'C++ > 문법 정리' 카테고리의 다른 글
[C++] C++ 언어는 왜 사용하는 걸까 (0) | 2025.01.24 |
---|---|
[C++] STL 컨테이너 선택 가이드 (0) | 2025.01.03 |
[C++] Template의 사용법 (0) | 2024.12.30 |
[C++] Dangling Pointer 대신 Smart Pointer 로 (1) | 2024.12.30 |
[C++] 오버로딩 vs 오버라이딩 (1) | 2024.12.27 |