객체지향 이야기 – 5.C++ 인터페이스

대한민국 개발자와 객체지향 이야기 – 5.C++ 인터페이스

미켈란젤로는 시스티나 성당의 천장 벽화를 그릴 때 구석에 있는 조그마한 인물까지 꼼꼼히 그리는 섬세함을 보였다. 누가 알아보겠냐는 질문에 “내가 알지”라는 말로 답했다. 개발을 하다보면 동료나 다른 개발자가 개발하는 라이브러리나 프로그램을 제작 하는 경우도 있다. 물론 개발 시 다른 어떤 요소보다 주어진 상황을 좁히고 요구 명세를 수렴하는 게 중요하다. 하지만 미켈란 젤로처럼 현재 요구사항에 딱 맞는 프로그램을 완성하는 것 만이 끝은 아니다. 제작될 프로그램이나 라이브러리에서 사용자를 고려해 확장성에 물꼬를 터주는 일은 개발자에게 있어 시스티나 성당 구석의 조그마한 인물을 그려 주는 일만큼 중요하다. 객체지향 언어에서 확장성의 핵심인 인터페이스의 정의를 알아보고 실제 사례를 분석해 본다.

정명수 ㅣmsguns.jung@samsung.com ㅣ 삼성전자 메모리사업부 플래시 소프트웨어 개발 관련 연구원

필자가 대한민국 개발자와 객체지향 이야기라는 주제로 칼럼을 쓴지도 벌써 10개월이 지났다. 객체지향 언어가 제공하는 고급 기술을 꽃에 비유한다면 이제는 꽃이 활짝 필 수 있도록 만드는 기술을 끝으로 객체지향 이야기를 마무리 할까 한다. 설계자, 사용자 모두에게 편리함을 제공하는 인터페이스 기술을 알아보고, 사례를 바탕으로 C++에서 어떻게 적용 할 수 있는지 살펴보자.

추상 클래스

지금까지 상속을 설계하고 디자인 이슈들을 살펴보며 만들었던 클래스들을 다시 한 번 정리해보자. <그림 1>과 같이 객체지향 패러다임에서 클래스는 구체 클래스(Concrete Class)와 추상 클래스(Abstract Class)로 나눠진다. 구체 클래스는 구현된 시스템의 클래스 계층도에 따라 단말 클래스(Leaf class)인지 또 다른 상속 관계에 있는 비단말 클래스(Non-leaf class)인지 구분한다. 여기서 짚어 볼 것이 추상 클래스에 대한 고찰이다.

<그림>

추상 클래스라는 용어는 간혹 혼돈을 초래한다. 상황에 따라 두 가지 의미를 내포한다. 단지 추상 클래스로 구현할 경우에는 설계도나 코드의 문맥에서 추상 클래스가 갖는 의미를 찾는다. 추상 클래스의 가장 보편적 의미는 오브젝트를 인스턴시에이션 시키지 않는 클래스를 말한다. 이런 의미의 추상 클래스는 <그림 1>에서 쉽게 파악 할 수 있다. 추상 클래스는 Object Instance라는 객체를 통해 인스턴시에이션을 갖지 않으므로 구체 클래스와 달리 그 실체가 없다. 다시 말해 프로그램에서 직접적으로 객체를 만들지 않는 클래스이다. 단순히 클래스 계층도에서 중복되는 코드들을 떠맡기 위해 사용되거나 하위 클래스의 인터페이스를 명세하기 위해 사용되는 클래스이다. 이제 사용되는 예를 살펴보자. 흔히 사용하는 MFC에서 추상 클래스는 CObject라는 이름으로 존재한다.

 

 

 

<그림>

MFC의 설계를 아는 게 목적이 아니므로 조금 간추려서 그 내용을 살펴보자. CObject는 순수 가상함수(현 코드에서는 소멸자)를 최소 한 개를 가지는 ABC이다. 또 시리얼라이즈 같은 개발자를 위한 인터페이스의 의미가 훨씬 강하다는 것을 순수 가상함수를 통해 알 수 있다. 이러한 CObject는 추상 클래스로써 하위 클래스의 인터페이스를 명세 하는 게 목적이다. 하위 클래스의 인터페이스를 명세 한다는 말은 CObject를 통해 파생되는 모든 클래스에서 사용 가능한 메소드의 각 시그니쳐를 정의한다는 것이다. 즉 CObject로부터 상속받는 개발자의 모든 코드는 데이터 저장 및 로딩을 수행하기 위해 시리얼라이즈를 사용한다. 시리얼라이즈는 아카이브를 통해 가능 하다는 것을 미리 정의하는 것이다.

인스턴시에이션이 존재하는 추상 클래스

이상하게 들릴 수도 있다. 추상클래스의 첫 번째 의미가 인스턴시에이션(Instantiation)을 시키지 않는 일관된 메소드의 행동에 대한 정의라고 한다면 이와 반대로 클래스를 인스턴시에이션을 시켜서 행동을 정의하는 추상 클래스가 그 두 번째 의미가 된다. 인스턴시에이션을 통해 추상 클래스를 지원하는 최초 언어는 Ada이다. Ada에서는 상속을 통한 코드 재사용이 불가능하기 때문에 추상 클래스를 통해 코드를 재사용하는 변칙(?)기법을 사용했다. 필자나 독자들이 좀 더 쉽게 이해할 수 있는 예제는 C++의 템플릿 클래스이다. 이는 이름 그대로 여러 종류의 클래스를 대표하는 범용적인 클래스로써 개발자의 코딩 부담을 줄여주기 위해 존재한다.

템플릿이 가장 잘 정의된 예는 STL과 같은 표준 템플릿 라이브러리이다. 템플릿은 Ada에서 그랬듯이 기본적으로 상속을 통한 코드 재사용으로 보기 어렵다. 예를 들어 C++를 생각해보자. 범용적인 큐(Queue)를 사용하기 위해 우선적으로 큐에 대한 클래스를 정의한다(표준 템플릿 라이브러리는 이러한 클래스 정의를 마친 후에 보여주는 덩어리이므로 인스턴스 클래스로써 재정의만 하면 된다). 정의된 클래스를 가지고 Queue, Queue, Queue 식으로 큐의 클래스에 인스턴스 클래스를 작성해 사용한다. 다른 매개인자(Parameter)를 갖는 클래스(Parameterized class), 범용 클래스(Generic class)와 같은 이름으로 불리는 템플릿은 인스턴스 클래스를 작성해서 쓰는 것이 일반적이다. 단, 인스턴스 클래스가 인스턴스 객체가 아님을 주의해야 한다. 인스턴스 클래스는 bound element라고 부르기도 하는데 추상 클래스가 타입(Type)을 인자(Argument)처럼 처리하기 때문에 인스턴스 클래스를 선언하는 행위는 인스턴스 객체가 될 수 없다.

템플릿은 처음 말했듯이 인스턴시에이션을 하지 않는 추상 클래스와 인스턴시에이션 문제 외에 현저하게 다른 특징을 가진다. 즉 추상 클래스와 관련된 시스템 작업이 모두 정적으로(Static) 컴파일 타임에 이뤄진다. 템플릿과 같은 추상 클래스가 컴파일 타임에 정적으로 모두 할당 된다는 말은 이를 추상 클래스로 볼 수 있는 가에 대한 의문을 남긴다. 폴리모피즘을 위한 동적 바인딩 시스템을 사용할 수 없고 상속과 다른 계통의 정제화 과정(refinement)을 통해 코드를 재사용하는 템플릿 클래스가 추상 클래스로 정의될 수 있는지 의문이 생기지만 현재는 추상 클래스로 인정하는 추세이다.

템플릿 형태의 추상 클래스에 대한 고찰

C++에서 추상 클래스가 도입 된 것은 C++ 3.0 버전 이후다. 앞서 언급했듯이 C++에 템플릿 형태의 추상 클래스가 도입된 것은 템플릿의 기능이 개발자의 코딩 량을 현저하게 감소시키기 때문이다. 코딩 량의 감소라는 매력과 자료구조나 특정 알고리즘을 몰라도 개발이 가능한 점은 초보 개발자에게 큰 장점으로 다가온다. 하지만 여기서 간과하지 말아야 할 것은 코딩 량은 줄지만 실제 코드 사이즈, 즉 오브젝트 코드의 분량이 줄어든 건 아니다. 컴파일러는 템플릿의 실체를 생성하기 위해 매크로 확장(Macro extension)방식을 이용한다. 알다시에 교체하는 역할만 수행하므로 실행 시 이미지 사이즈가 템플릿을 쓰지 않고 잘 설계된 프로그램 보다 크다.

그런데 어떤 일이든지 개선점은 있는 법이라 이제까지 제안된 방법 중에서 가장 인정 받고 있는 것이지만 더 들여다보면 또 다른 개선점을 도출할 수 있다. 필자는 요구사항을 획득할 수 있는 좋은 수단으로서 시스템 개발 초기부터 UI 프로토타이핑을 함께 쓸 것을 적극 권하고 있다. 그리고 만일 유스케이스와 결합해 사용한다면 시너지 효과 덕분에 더 큰 성과를 낼 수 있다.

이미지 사이즈 문제뿐만 아니라 프로젝트 운용 입장에서도 어려움이 있다. UserClass나 int에 대한 큐 클래스를 제작할 때 Queue, Queue와 같이 템플릿을 써서 구현하는 것 보다 상속 기능을 이용해 시스템을 구성하는 게 훨씬 유연하다. int, UserClass와 같은 타입에 연관되는 연산들, 예를 들어 Insert()와 같은 연산이 수행하는 실질적인 행위가 각 타입에 따라 이질적인 형태를 취할 수 있기 때문이다. 각 타입의 클래스에서 insert와 같은 연산이 차이가 없는 비슷한 형태의 골격을 유지한다면 템플릿을 사용해도 큰 문제가 없지만 서로 다른 양식에 따라 구현될 경우 템플릿의 사용이 도움 되지 않는다. 또한 템플릿에 들어가는 타입들은 서로 특별한 관련이 없어도 같은 형태의 템플릿 클래스를 통해 구현되므로 LSP 문제를 근본적으로 떠안을 수밖에 없다.

더욱이 동적 바인딩을 통한 유연성을 확보하기 위해 템플릿 사용을 자제하는 것이 올바르다. 템플릿은 초보 개발자에게 마법처럼 보일 수 있지만 컴파일러가 매크로 확장을 통해 단지 코드를 복사한다는 사실을 알면 객체지향을 하면서 Copy & paste를 하는 C 코드와 다를 바가 없다. 실제로 템플릿을 대신해 각 클래스의 골격을 생성하거나 복사하는 작업을 수행하는 CASE 도구 등을 통해 같은 효과를 얻을 수 있다.

템플릿은 객체지향인가?

필자가 학창 시절에 한참 목에 핏대를 세워가며 주장했던 부분이 바로 템플릿이다. 필자는 범용 컨테이너를 모르던 시절 대부분의 자료구조를 직접 만들어서 사용했다. 잘 만들어서가 아니라 단지 STL이나 ATL과 같은 템플릿을 몰랐기 때문이다. STL 내부를 접해 본 독자들은 알겠지만, STL을 조금이라도 경험했을 때, 필자는 소프트웨어에서 침범할 수 없는 네버랜드를 본 기분이 들었다.

지금도 STL 같은 잘 만들어진 템플릿을 사용하는 것이 검증되지 않은 컨테이너를 사용하는 것보다 훨씬 유용하고 정확한 퍼포먼스를 보장한다고 생각한다. 하지만 STL의 모태인 템플릿은 객체지향으로 분류하기는 좀 애매하다는 게 필자의 견해다. 탬플릿 형태는 추상화 클래스에 대한 고찰에서도 언급했듯이 재사용 성을 상속이 아닌 정제화를 통해 한다는 점과 정적 바인딩을 사용하지 못하는 치명적인 약점 이외에도 객체지향의 원류인 스몰토크에서 템플릿을 지원하지 않는 점도 주목할 필요가 있다. 스몰토크에서 템플릿을 지원하지 않는 이유는 템플릿 없이 템플릿 보다 더 훌륭한 범용 컨테이너를 제작할 수 있기 때문이다.

그렇다고 템플릿이 객체지향 언어에서 다중상속 만큼 배제돼야 한다는 말은 아니다. 템플릿의 유용성은 ATL/COM 환경에서 많은 템플릿을 통해 개발자의 부담을 덜어주며(물론 유사한 EJB 환경에서 컴포넌트 제작이 템플릿을 사용하지 않다는 점도 고려해야 한다), STL과 같은 막강한 라이브러리들은 개발자가 소프트웨어에서 빈번하게 쓰는 자료구조와 알고리즘을 벗어나 좀 더 클래스간의 관계를 통한 시스템 구성을 구현하는데 도움을 준다는 점과 쉽게 개발하도록 도와준다는 점에서 객체지향에서 없어서는 안 될 존재이다.

하지만 정적 바인딩과 같은 치명적 템플릿 클래스 구현의 약점은 C++가 극복할 문제이다. 템플릿을 지원하지 않는 자바의 경우도 제네릭 프로그래밍(Generic programming)이라는 타이틀 아래 자바 제레릭을 자바 5.0부터 이와 유사한 기능을 지원한다. 자바 제네릭이 타입캐스팅에 대한 문제와 컴파일 타임 시 타입 안정성을 제공하는 것과 함께 템플릿 클래스의 정보은닉 문제에 C++와 다른 정책을 펴는 것도 C++가 앞으로 발전할 수 있는 가능성을 제시한다. Java Generics를 사용하는 클래스들의 모든 인스턴스가 컴파일과 런타임 시 바인딩을 고려한다는 것은 매우 고무적인 사실이다.

객체지향에 있어서 인터페이스

인터페이스라는 용어는 객체지향과 관련 없이 사용되기 때문에 더욱 혼돈스러울 가능성이 있다. 일반적인 의미로 사용되는 인터페이스는 ‘컴퓨터 시스템을 구성하는 요소들을 연결하는 점’의 의미이다. 객체지향과 관련해 인터페이스는 소프트웨어를 작성하는 도구로 사용되기 때문에 객체지향 패러다임에서 사용되는 전자의 인터페이스와는 그 정의가 사뭇 다르다. 지난 시간에 언급했듯이 객체지향 문화에서는 하나의 용어가 서로 다른 의미로 사용되는 경우가 흔하다. 객체지향도 인터페이스도 문맥에 따라 다른 의미를 갖는다.

스펙으로서의 의미

프로그래밍 시 사용되는 인터페이스라는 용어가 갖는 하나의 의미는 API에서 사용되는 인터페이스를 말한다. 이는 사용자 관점에서 공급된 소프트웨어의 사용법을 나타내는 스펙으로 일종의 Export된 SDK 정의와 같다. SDK(Software Development Kit)는 특정 플랫폼에서 응용 프로그램을 개발 하기 위한 함수 집합을 의미하는데 라이브러리 형태로 제공되는 함수의 용도와 사용법을 말하며 윈도우에서는 Win32 API들이 그러한 예이다. 이러한 스펙은 소프트웨어의 공급자와 소비자를 분리 함에 있어 구현을 소비자의 사용 측면으로부터 분리시켜 은닉하는 게 목적이다. 이러한 정보 은닉을 전제로 한 스펙 생성은 대규모 프로젝트를 이행하거나 관리 할 때 매우 유용하게 쓰인다. 즉 객체지향에서 인터페이스는 특정 클래스의 스펙으로 볼 수 있다.

뷰 관점

시스템을 개발 하거나 설계를 하다 보면 특정 객체가 갖는 속성 이외에 몇몇 사용자가 그 객체를 바라보는 뷰에 의해 특별한 명세를 제공할 때가 있다. 특정 객체가 자료 추상화의 원칙에 의해 실세계가 갖는 모든 속성과 행동을 정의하지 못하기 때문이다. 이렇게 어떤 객체가 속하는 클래스에 정의된 기능 이외에 특정한 기능이 필요 할 때 사용하는 추상화 도구가 인터페이스다.

예를 들어보자. 필자는 개발자로서 직장인이라는 계층 군에 들어간다. 직장인은 봉급을 받거나 일을 하고 문서를 작성하는 행위 등이 정의됐다. <그림 2>처럼 사람으로 상속받아 일을 하는 개발자라는 클래스가 비로소 필자의 클래스가 된다. 만약 독자들이 필자를 본다면 C++에 대한 글을 쓰는 개발자나 글을 쓰기 위해 swblog.net이라는 소프트웨어 블로그를 운영하는 개발자라는 특정한 요구명세가 생길 수 있다. 그렇다고 해서 글을 쓰거나 블로그를 운영하는 메소드를 개발자 클래스에 삽입할 수는 없다. 모든 개발자가 글을 쓰거나 블로그를 운영하지는 않기 때문이다.

<그림 2>

<그림 2>을 보고 다중 상속이라고 말할지도 모르겠다. 지난 호에서 다중 상속을 사용할 때 그 모델을 사용하지 않는 쪽으로 권고했기 때문에 더욱 의아해 할 수 있다. 하지만 <그림 2>는 지난 호에서 논의 됐던 다중 상속과는 본질 자체가 다르다. <그림 2>는 자바의 인터페이스를 통한 다중 상속처럼 이해 될 수 있는데 이에 대해서는 상속에 대해 구현 상속과 인터페이스 상속, 이 두 가지에 대한 본질적 의미를 이해해야 한다.

구현 상속은 일반적 의미의 상속과 일맥상통한다. 상속을 통해 자식 클래스가 부모 클래스의 모든 속성과 메소드 내용을 물려받는 것을 의미한다. 이런 경우는 사실 구현 모두를 물려받는 것으로 볼 수 있다. 자식 클래스가 인스턴시에이션이 이뤄짐과 동시에 부모 클래스의 데이터 멤버들이 모두 생성되고 생성자에 의해 초기화 되며 메소드의 구현 부분도 그대로 상속됐으므로 자식 클래스에서 특별히 상위 클래스의 메소드를 오버라이드 하지 않더라도 상속받은 메소드를 그대로 사용하는 반면, 인터페이스 상속은 상위 클래스의 데이터 멤버와 메소드를 모두 물려받는 게 아니라 부모 클래스의 명세만을 물려받는 것이다. 명세만을 물려받는 다는 것은 앞서 말한 스펙의로써 인터페이스 의미에서 언급했듯이 부모 클래스에서 정의된 멤버 함수들의 시그니쳐만 물려받는 것으로 자식 클래스에서는 반드시 부모 클래스에서 정의된 메소드들을 구현해야 한다.

인터페이스 상속과 구현상속 일부를 결합한 <그림 2>의 계층도는 개발자와 필자라는 두 가지 클래스를 구현 상속으로 이용하는 게 아니므로 다중 상속이라고 볼 수 없다. 지난 호에 잠시 언급했듯이 자바나 C#이 다중 상속을 사용하기 위해 인터페이스를 도입했다고 소개 하거나 인터페이스를 통해 다중 상속을 구현할 수 있다는 말은 이러한 이유에서 잘못된 설명이다.

범용 자료구조 구현을 위한 인터페이스의 사용

그간 자료구조를 사용하면서 많은 고민을 했다. 자료구조가 행동해야 하는 정의는 일정한데 반해, 자료구조의 속성이 계속 변화하기 때문에 같은 요구사항을 갖는 자료구조에 대해서도 여러 가지 구현을 생성했다. 이 문제를 다시 생각해보자. 본질적으로 어떤 자료구조의 행동을 정의할 때 자료구조가 다루는 속성이 미리 정해지는 게 올바른 것일까?

C++는 자료 구조의 행동에 대한 정의와 속성의 분리를 템플릿이라는 기술을 써서 간결하게 처리했다. 이런 템플릿은 범용적인 자료구조를 구현할 때 매우 편리하다. 하지만 앞서 언급했듯이 큐와 같은 범용 자료구조에 정수(int), 실수(float), 스트링(string), 사용자 클래스 등이 번갈아 가며 입력된다면 어떨까? 템플릿과 같은 방법으로는 이를 해결 할 수 없지만 인터페이스를 쓰면 템플릿과 달리 동적으로 정수, 실수, 스트링, 사용자 클래스 등을 다루는 큐를 정의한다.

우선 큐의 기본적인 행동을 정의할 구체 클래스를 생성하고 이를 처리할 내부 원소인 Entry를 인터페이스로 구현한다. Entry를 상속해 각 실수, 스트링, 사용자 클래스 등을 구현하면 완전한 범용 자료구조가 생성된다. 우선 인터페이스를 사용할 수 있는 자바를 써서 큐를 생성해보자.

자바로 생성한 코드라도 인터페이스를 통해 제작한 QueueEntry라는 자료구조와 큐라는 알고리즘이 분리된 것을 알아보는데 아무런 문제가 없다. 큐라는 클래스를 사용할 때 특별한 자료구조 타입을 고려하지 않고 일방적인 방법을 통해 Push, Pop과 같은 행동을 취한다.

 

 

 

<그림>

CBSE에서의 인터페이스 사용

인터페이스의 응용을 알아보기 전에 인터페이스가 빛을 바래고 있는 부분을 살펴보자. 사실 CBSE는 객체지향 패러다임에서 언급 가능한 범위를 넘어선다. 하지만 COM, CORBA, EJB와 같은 컴포넌트 기술에서 인터페이스가 어떤 의미를 갖는지 알아볼 필요가 있다. CBSE에서 인터페이스는 클라이언트가 컴포넌트 객체의 서비스를 액세스 할 수 있는 수단을 제공한다. 서버로 동작하는 컴포넌트는 그 컴포넌트가 제공하는 인터페이스들을 실제로 구현해야 한다. 이는 객체지향 언어에서 말하는 구현과 유사하다. 이와 반대로 클라이언트로 동작하는 컴포넌트들은 서버 컴포넌트의 인터페이스를 기초로 응용, 작성돼야 한다. 인터페이스를 이용하는 기법들은 COM, CORBA, EJB에서 서로 유사한 부분을 갖고 있다. 추상 클래스로 인터페이스를 명세 하는 것과 유사하게 CBSE의 컴포넌트 기술들은 IDL(Interface Definition Language)를 통해 명세 한다.

 

 

 

<그림>

<리스트 3>에서 명세 된 IMicroSoftware 인터페이스를 구현하는 서버의 경우 <리스트 3>에서 정의된 GetPaper와 SetPater의 함수를 통해 그 행동을 정의한다. 이 컴포넌트를 개발하는 개발자는 구현 내역을 클라이언트에게 전혀 공개 할 필요가 없다. 물론 바꿔 말하면 이 컴포넌트를 사용해 개발하는 클라이언트 개발자는 IDL외에 관련된 구현 내역을 전혀 알 필요가 없고, IDL만을 가지고 개발하며 서버 컴포넌트 구현 시에 사용됐던 헤더 파일이나 구현된 바이너리 코드와 링크할 필요가 전혀 없다. 이런 관점에서 볼 때 CBSE에서 인터페이스는 정보 은닉 수단으로서의 의미가 강하다(아직 논란의 여지가 있으나 개발자 입장에서 봤을 때 가장 현실적인 의미가 정보 은닉 수단 인 것 같다). 사용자 입장에서는 CoCreateInstance, QueryInterface와 같은 메소드를 제외하면 객체지향 프로그램을 작성 하듯이 코딩 할 수 있다. 예를 들면 IMaso->GetPaper와 같은 식이다.

여기서 말하는 것은 COM, EJB와 같은 CBSE를 논하는 게 아니라 컴포넌트 기술이 인터페이스를 이용해 컴포넌트가 제공하는 서비스를 외부에 공개하므로 인터페이스 사용법에 친숙할 필요가 있다. 대부분의 전문가들은 앞으로 컴포넌트를 기술을 이용한 개발이 보편화 될 것으로 예상한다. 이 기술에 필수 요소가 인터페이스라는 점은 여러 C++ 개발자들에게 무척 고무적인 일이다.

 

 

 

<그림>

C++에 있어서 인터페이스

잠시 쉬어가는 의미로 이 질문에 대답해 보자. “ C++로 시스템을 작성하면서 몇 개의 인터페이스를 정의했는가?” 적어도 이 글을 읽고 있는 독자라면 1개, 2개, 또는 “음… 나는 사용자를 위해 C++에서 많은 인터페이스를 열어 줬는데”라는 답변은 나오지 않아야 한다. 정확히 말하면 C++는 인터페이스를 갖지 않기 때문이다. C로부터 개발을 진행해 C++로 전향하게 된 개발자뿐만 아니라 대부분의 C++ 개발자들은 인터페이스 사용에 대한 포괄적인 지식이나 개념 이해를 갖고 있지 않다. C++는 자바와 같이 인터페이스에 대한 지식 및 개념 이해가 없이도 충분히 프로그래밍이 가능하기 때문이다. C++는 왜 인터페이스를 사용하지 않은 것일까?

당시 C++의 이름은 ‘C with Data Abstraction’이다(1980년에 개발돼 27년이 지났는데도 아직까지 몇몇 개발자는 C++를 C With Data Abstraction처럼 사용한다. 이는 C++가 객체지향에 대한 개념이 성숙해지기 전에 C개발자에게 보급됐다는 사실을 알 수 있다). C++는 자바와 달리 객체지향 패러다임을 구현하기 위한 목적으로 만든 게 아니라 구조적 언어에 추가로 객체지향 패러다임을 적용한 언어이므로 인터페이스 도입이 이뤄지지 않았다(C++ 릴리즈 3.0이 배포된 년도가 1990년이다).

C++를 사용하면서 인터페이스를 사용하지 않고도 충분한 시스템을 제작 할 수 있는 것은 코딩을 통해 문제를 해결 할 때 반드시 인터페이스를 사용 할 필요는 없기 때문이다. 절차적 언어를 사용해도 표현 방법이 다를 뿐 구현상의 문제는 없을 뿐 더러, C++는 절차적 언어에서 출발했기 때문에 절차적 방법을 충분히 이용 할 수 있다. 더불어 다중 상속을 지원하므로 이를 통해 여러 뷰를 생성한다. 템플릿을 쓰지 않고 앞서 구현한 자바의 큐를 C++로 구현 한다면 어떠한 식으로 표현할까?

앞서 언급했듯이 C++는 자바처럼 인터페이스 같은 도구가 존재하지 않으므로 자바에서처럼 명시적으로 인터페이스를 만들 수 없다. 하지만 늘 그랬듯이 C++는 지원하지 않는 기능에 대해 모방할 수 있는 기초 모델들을 지원 하는데 인터페이스를 구현하기 위해 C++에서는 가상함수와 다중 상속을 이용한다.

 

 

 

<그림>

객체지향이 주는 의미

개발자에게 있어 중요한 자질은 객체지향 패러다임을 익숙하게 다루기보다는 문제를 정확히 정의하고 처리 할 수 있는 능력, 프로그램을 제작하기에 전에 자신의 코드가 얼만 큼의 퍼포먼스를 낼지 예측하고 관리하는 능력 등이 훨씬 중요한 부분이다. 마이크로소프에서는 이러한 SDE계층(Software Develop Engineering)의 역량에 대해 정확히 정의한다. 이런 논리적 사고 이외에도 실제 프로젝트를 운용 하는데 있어서는 유지 보수, 요구 사항 관리, 프로세스간의 정확한 문서, 확장성을 고려한 설계 등, 개발자들이 알아야 할 부분이 산재해 있다. 개발 시간을 단축하고 좀 더 개발자가 개발에 몰두 할 수 있도록 많은 소소한 작업들을 대신 해주는 객체지향 언어를 사용 하면서 이를 단지 추상화 도구로만 사용 할 것이 아니라 그 숨은 기능들의 의미를 제대로 파악하고 사용하는 것이 개발자의 몫일 것이다.

마지막으로 항상 필자에게 촉매제 역할을 하는 박찬익 책임, 부족하기만 한 개발자에게 새로운 영역에 대한 많은 가르침을 주는 김성철 책임, 장세정 선임, 옆에서 묵묵히 지켜 봐준 삼성테크윈 강선정 연구원에게 감사 인사를 드린다. 연재는 끝났지만 필자의 블로그(http://www.swblog.net)를 통해 현재 다루지 못한 STL과 Generics에 대한 비교, C와 C++의 호환을 위한 테크닉 등, C++에 남겨진 주제들과 개발의 일상을 함께 공유 할 수 있기를 기대한다.

제공 : DB포탈사이트 DBguide.net
출처 : 마이크로소프트웨어 2007년 12월

답글 남기기