C 언어의 확장판인 C++
C++은 C언어에 '객체 지향 프로그래밍' 기능이 추가되어 만들어진 언어입니다. 마치 웹 개발에 주로 쓰이는 TypeScript라는 언어가 JavaScript에 '타입' 기능이 추가되어 만들어진 것처럼 말입니다. 따라서 C언어의 문법은 C++에서도 모두 그대로 쓰입니다.
C언어는 절차를 중시하는 '절차 지향' 언어임에 반해 C++는 객체라는 데이터가 중심인 '객체 지향' 언어입니다. 하지만 C++에서도 C언어의 문법은 모두 지원되기 때문에 C++로 코드를 절차적 방식으로 작성하더라도 문제가 되진 않습니다. 다만 대부분 규모가 큰 소프트웨어를 만들 때는 객체 지향을 사용하는 것이 편리할 뿐 아니라 유지 보수 및 관리에도 용이합니다. 그럼 이 '객체 지향 프로그래밍'이란 것이 무엇인지 한 번 빠르게 짚어보도록 하겠습니다.
객체 지향 프로그래밍 (OOP)
객체 지향 프로그래밍을 이해하기 위해선 우선 '객체'에 대한 이해가 선행되어야 합니다. 지극히 당연한 말이긴 합니다만..
객체(Object)란 어떤 사물을 '데이터와 절차의 묶음'으로 표현한 것입니다. 좀 더 쉽게 설명하기 위해 어떤 계산 프로그램을 예로 들면, 프로그램 코드 내에서 계산기라는 사물은 (값을 저장하는) 변수와 (덧셈, 뻴셈 등의 기능을 수행하는) 함수로 추상화되어 하나의 '객체'로 표현할 수 있습니다. 여기서 추상화란 사물의 특징과 동작을 조사하여 객체로 만들기 위해 인터페이스를 설계하는 것을 말합니다.
객체는 독립적이고 재활용성이 높아 하나의 부품으로써 여러 프로그램에 재사용될 수 있습니다. 마치 다이오드, 트랜지스터, 저항과 같은 하드웨어 부품들이 여러 제품에서도 재활용될 수 있는 것처럼 말입니다. 라디오 부품 조립 키드에 들어있는 여러 하드웨어 부품을 조립해서 라디오를 만들듯이, 여러 독립적인 객체를 조합하여 자신이 원하는 기능 혹은 하나의 완성된 프로그램을 구현하는 프로그래밍 방식을 객체 지향 프로그래밍(OOP / Object Oriented Programming)이라 말합니다.
즉 객체 지향적으로 프로그램을 짠다는 것은
- 우선 문제의 핵심인 데이터(변수)를 정의하고
- 이 데이터에 절차(함수)를 결합하여 현실의 사물을 표현할 수 있는 객체를 만든 후
- 이런 독립적인 객체를 조립하여 프로그램을 완성해 나가는 방식으로
프로그래밍을 하는 것이라 설명할 수 있습니다.
객체 지향 프로그래밍의 등장 배경
그럼 다음으로 이러한 객체 지향 프로그래밍 방식이 등장하게 된 배경을 간단히 설명하겠습니다. 초기의 컴퓨터는 극히 제한된 분야에서만 사용되었고 가격 또한 매우 비쌌습니다. 하지만 하드웨어의 급격한 발전에 발맞춰 컴퓨터는 급속도로 일반 사람들에게 보급화 되었습니다. 이에 따라 사람들은 컴퓨터를 통해 강력하고 편리한 소프트웨어 프로그램을 사용하길 기대하고 이를 요구하기 시작했습니다.
그러나 눈부신 하드웨어의 발전과는 반대로, 소프트웨어의 발전은 매우 느리게 진행되었습니다. 그 주요한 이유 중 하나는 기존의 절차적 프로그래밍 방식이 (사람들이 요구하는) 규모가 크고 복잡한 소프트웨어를 질적으로 완성도 있게 만들어주지 못했기 때문입니다. 또한 그 당시 개발 인력이 부족했던 것도 소프트웨어의 느린 발전의 큰 원인이었습니다.
따라서 이러한 문제를 해결하기 위해 절차적 프로그래밍을 대체할 여러 개발 기법들이 제시되었는데, 그 중 가장 좋은 방식으로 선택된 것이 바로 '객체 지향 프로그래밍' 방식입니다.
객체 지향 프로그래밍 방식은 조립식이기 때문에 결과물의 성능(속도와 크기)이 절차적 방식에 비해 조금 떨어진다는 단점이 있습니다. 그러나 하드웨어의 발전에 힘입어 그 정도의 차이는 무시해도 될 만큼 미미하다고 합니다. 현대의 개발 관건은 프로그램의 성능보단 오히려 개발 용이성과 유지 보수, 편의성, 신뢰성입니다. 인건비가 하드웨어보다 훨씬 더 비싸고 개발 기간이 곧 비용과 직결되기 때문에 얼마나 빨리 정확한 소프트웨어를 생산하는가가 현대 개발의 관건이며, 그 해답이 바로 객체 지향 프로그래밍입니다.
객체 지향 프로그래밍의 특징
객체 지향 프로그래밍 방식엔 총 5가지 일반적인 특징이 있습니다. 다만 사람에 따라 특징에 대한 견해가 달라질 수 있다고 합니다.
캡슐화 (Encapsulation)
캡슐화란 어떤 사물의 특징을 나타내는 데이터와 이를 관리하는 사물의 동작(함수)로 추상화하여 이들을 하나의 단위(캡슐)로 묶는 것을 말합니다. 즉, 캡슐화를 '객체를 만드는 행위'라고 설명해도 될 것 같습니다. 캡슐화를 통해 만들어진 객체는 스스로 독립적이며 프로그램의 부품으로 활용될 수 있습니다.
정보 은닉 (Information Hiding)
객체의 데이터와 함수 중 외부에서 사용하는 기능만 공개하고 나머지는 숨길 수 있는데 이를 정보 은폐 혹은 정보 은닉이라 합니다. 정보를 은닉하는 이유는 외부에서 객체의 상태를 마음대로 변경하거나 허가되지 않은 동작을 요청하지 못하도록 하여 스스로의 안전성을 확보하기 위해서입니다. 이를 통해 객체는 더욱 견고하게 캡슐화됩니다.
추상화 (Abstraction)
추상화란 객체의 효율적이고도 안전한 사용을 위해 인터페이스를 설계하는 것이며 캡슐화와 정보 은닉에 의해 구현됩니다. 현실의 사물을 객체로 표현하기 위해서는 이 사물이 어떤 특징을 가지며 어떤 동작이 가능한지를 조사해야 한다고 위에서 언급한 바 있는데, 이를 '데이터 모델링'이라 합니다. 모델링의 결과 필요한 자료와 동작의 목록이 작성되면 이들을 캡슐화해서 객체로 정의합니다. 그리고 외부에서 사용할 기능은 공개하고 제한할 기능은 숨깁니다.
상속 (Inheritance)
상속은 이미 만들어진 클래스를 바탕으로 새로운 클래스를 정의하는 기법입니다. 파생된 클래스는 자식 클래스라 불리며 기존 클래스의 모든 속성과 동작을 물려받습니다. 또한 여기에 더 필요한 기능을 추가하거나 필요 없는 기능을 제거 또는 변경할 수 있습니다. 객체를 아무리 추상적으로 잘 정의해 놓았다 하더라도 현실의 문제는 특수하기 때문에 모든 경우에 일반적으로 적용되지는 않습니다. 이런 상황에선 객체를 상속 받아 원하는 부분만 수정하여 사용하는 방식으로 기존 객체를 최대한 재활용함으로써 작업의 생산성을 끌어올립니다.
다형성 (Polymorphism)
똑같은 호출이라도 상황에 따라, 호출하는 객체에 따라 다른 동작을 할 수 있는 능력을 다형성이라고 합니다. 실제 내부 구현은 다르더라도 개념적으로 동일한 동작을 하는 함수를 하나의 인터페이스로 호출할 수 있으므로 객체들을 사용하는 코드를 일관되게 유지할 수 있습니다. 다형성은 동적 바인딩을 하는 가상 함수에 의해 구현됩니다.
< 참고 자료 >
- 서적 ⌜C++ 에스프레소⌟
- SoEn:소프트웨어 공학 연구소