프로그래밍/cpp

C++ 추상클래스(인터페이스(interface)/순수가상함수)에 대한 고찰

콘파냐 2014. 5. 1. 19:19
반응형

디자인 패턴에 관한 책을 보면 인터페이스를 많이 활용합니다. 그런데 C++에서는 인터페이스라는 용어를 정확히 찝어서 사용하지는 않는 것 같습니다. 자바(Java)언어의 경우를 보면 일반적인 클래스와 인터페이스가 확실히 구별되고, 구현 방법도 extends와 implements로 다른 종류로 치부됩니다. 애초에 자바의 경우는 언어적인 차원에서 다중상속을 하지 못하게 하였고, 대신 인터페이스를 구현하는 방법으로 다중 상속부분을 해결하는 걸로 알고 있습니다. 꼭 다중상속의 차원에서만은 아니겠지만, 자바언어는 인터페이스를(interface) 따로 정의해 놨습니다. 이에 반해서 다중 상속이 자유로운 C++의 경우는 인터페이스라는 용어에 대해서 굳이 생각하지 않아도 되고 굳이, 구분해서 문법을 설명하지 않습니다.


인터페이스(Interface)

인터페이스의 사전적 정의를 찾아보면 다음과 같습니다.

접속기,접점(두 시스템이 만나는 공유영역, 경계영역)

예를 들면 컴퓨터의 메모리에서 DDR,DDR1,DDR2,DDR3라는 메모리의 종류가 있고 또 DDR3메모리에서도 메모리크기,클럭 등 여러가지 스펙이 존재합니다. 그런데 DDR3라는 스펙만 같다면 DDR3를 지원하는 메인보드에 꼽을 수 있습니다. 여기서 메인보드에 메모리를 꼽는 부위를 인터페이스라고 합니다. 인터페이스는 DDR3과 DDR2가 서로 다릅니다.  DDR3를 구현한 메모리는 DDR3가 가지는 기본적인 스펙을 구현합니다. DDR2도 마찬가지구요.

이와 비슷하게 프로그래밍 언어에서 사용하는 인터페이스도 그 인터페이스를 구현하는 클래스가 존재하게 됩니다. DDR3슬롯만 만들었다면 아무 소용이 없고, DDR3인터페이스에 맞는 DDR3메모리를 만들어야(세부스펙은 다를수있음,1Gb,2Gb....) 하기 때문이죠.


위 메모리의 예에서도 알 수 있듯이 인터페이스는 기본적이며 공통적인 기능들이라 생각해도 됩니다. C++에서는 공통적인 기능을 하는 그 함수 자체를 인터페이스라고 부르기도 합니다.


메모리라면 필요한 공통적인 기능은 슬롯에 맞는 메모리의 크기도 있을 수 있겠고, 메모리의 용량, 내부적인 DDR1,2,3의 동작방식 등이 있을 수 있습니다. 이런 공통적인 부분은 꼭 필요한 부분이기 때문에 꼭 구현해야 하는 부분입니다. 이렇게 꼭 구현해야 하는 부분은 인터페이스로 따로  그 기능 목록을 만들어서 이를 사용하는 클래스들로 하여금 그 인터페이스를 상속하도록 하여 구현하도록 하는 것입니다. 이렇게 하면 이 기능 목록들을 구현하지 않을 경우 에러가 나게 되어, 필요한 기능을 꼭 구현하도록 강제할 수 있습니다.



순수가상함수와 추상 클래스


2013/06/04 - [프로그래밍/c++] - 가상함수 virtual 키워드 C++


2014/01/04 - [프로그래밍/c++] - 가상함수(virtual),vptr,vtable C++


2014/04/21 - [프로그래밍/c++] - c++ 생성자 소멸자/(virtual)가상 소멸자를 쓰는 이유


이미 virtual 키워드와 가상함수에 대해서는 살펴보았습니다. virtual키워드의 필요성은 참조에 의한 결합에서 동적결합을 하기 위함을 알고 있습니다. 이는 중요한 주제인 다형성과 관련된 이야기로 이어집니다. 이런 다형성을 좀 더 생각해보면 자식 클래스별로 같은 함수를 호출 하더라도 각 클래스별 특징적인 행동을 하도록 하는 것이 목적이었습니다. 이는 함수의 오버라이딩을 통해서 가능하였습니다. 부모 클래스는 이런 특정 함수를 선언만 해놓고 구현은 하지 않도록 하기도 하지요. 이를 인터페이스라고 이해해도 되겠습니다. 여기서 부모클래스에서 선언만 해놓고 순수가상함수로 지정하게되면 다음과 같은 특징이 생기게 됩니다.

첫째, 순수가상함수를 선언한 클래스는 인스턴스 생성을 할 수가 없습니다.

순수가상함수가 하나라도 있는 클래스를 추상클래스라고합니다. 다시 말해서 '추상클래스는 인스턴스를 생성할 수 없다' 입니다.

둘째, 추상클래스를 상속한 자식 클래스는  순수가상함수를 구현해야 인스턴스를 생성할 수 있습니다.

순수가상함수를 상속받았다 하더라도 인스턴스만 생성하지 않으면 에러는 발생하지 않습니다. 하지만 인스턴스를 생성하기위해서는 상속받은 순수가상함수를 모두 구현해야 됩니다.


다음과 형태는 순수 가상함수입니다.(C++)



interface라는 클래스안에 순수가상함수 test()가 선언되어 있습니다. 위 클래스는 위에 말한 2가지 특징을 모두 갖습니다.


자바의 경우는 구현방법이 다릅니다. 자바에서 인터페이스는 멤버함수가 모두 구현이 안된 순수가상함수입니다. 물론 =0이라는 표현도 쓰지않습니다. 대신 다음과 같이 선언합니다.

public interface A {

public void test();

}

그리고 자바에서 추상클래스는 순수가상함수와 구현된 함수가 섞여있는 클래스입니다. abstract키워드로 선언합니다.

C++은 자바에서 처럼 틀이 정해지지는 않았지만, 자바와 똑같이 사용할 수 있습니다. 대신 C++에서는 더 유연하기 때문에 실수없는 객체 지향적 설계를 하기에는 자바환경이 좋다고 생각듭니다.


인터페이스를 사용하는 이유

객체지향의 개념에 맞게 잘 정돈된 설계를 위해서 사용합니다. 굳이 인터페이스를 사용하지 않더라도 가능한 일이지만, 위에 메모리의 예처럼 규격을 정해주고 카테고리라는 것을 만들어 관리해야 나중에 재사용의 문제나 관리적 측면에서 편리할 것입니다. 하드디스크의 SATA와 IDE 인터페이스라는 규격을 정해두지 않고 회사별로 천차만별로 만든다면, 자신의 회사에서 만드는 제품군에서만 사용 가능할 것입니다. 이런 인터페이스를 정하게되면 회사간에 협업으로 개발하는 프로젝트의 경우도 편리해 질 것입니다. 인터페이스만 맞춰 놓고, 내부구현은 회사별로 어떻게 하든 상관없습니다. 여러가지 문제점도 생기겠지만, 우선 인터페이스만 맞추면 됩니다. 더 많은 이유들이 있겠지만, 공부가 부족한 저는 이 정도만 이해하고 있습니다.


2014/04/22 - [관심사/도서] - head first design patterns(객체지향 디자인 패턴) 서적(책)


인터페이스에대한 다양한 예제를 보고 싶으시다면 디자인 패턴을 공부하시면 됩니다. 

반응형