C++ 인터페이스: 추상 클래스와 순수 가상 함수 마스터하기
인터페이스(interface)는 특정 구현에 얽매이지 않고 C++ 클래스의 행동이나 능력을 기술합니다.
C++ 인터페이스는 추상 클래스(abstract classes)를 사용해 구현되며, 이 추상 클래스는 데이터 추상화(구현 세부 사항을 관련 데이터로부터 분리하는 개념)와 혼동되어서는 안 됩니다.
최소 하나의 함수를 순수 가상(pure virtual) 함수로 선언하면 클래스는 추상 클래스가 됩니다. 순수 가상 함수는 선언에 "= 0"을 배치해 지정합니다.
class Box {
public:
// 순수 가상 함수
virtual double getVolume() = 0;
private:
double length;
double breadth;
double height;
};
추상 클래스(흔히 ABC라 불림)의 목적은 다른 클래스들이 상속받을 적절한 기반 클래스를 제공하는 것입니다. 추상 클래스는 객체 인스턴스화에 사용할 수 없으며 오직 인터페이스 역할만 합니다. 추상 클래스의 객체 인스턴스화 시도는 컴파일 에러를 일으킵니다.
따라서 ABC의 서브클래스가 인스턴스화되려면 각 가상 함수를 구현해야 하며, 이는 ABC가 선언한 인터페이스를 지원함을 의미합니다. 파생 클래스에서 순수 가상 함수를 오버라이드하지 않고 해당 클래스의 객체를 인스턴스화하려 하면 컴파일 에러가 발생합니다.
객체 인스턴스화에 사용할 수 있는 클래스를 구체 클래스(concrete classes)라 부릅니다.
추상 클래스 예제
부모 클래스가 getArea() 함수 구현을 위한 인터페이스를 기반 클래스에 제공하는 다음 예제를 고려해 보세요.
Live Demo
#include <iostream>
using namespace std;
// 기반 클래스
class Shape {
public:
// 인터페이스 프레임워크를 제공하는 순수 가상 함수
virtual int getArea() = 0;
void setWidth(int w) { width = w; }
void setHeight(int h) { height = h; }
protected:
int width;
int height;
};
// 파생 클래스
class Rectangle: public Shape {
public:
int getArea() { return (width * height); }
};
class Triangle: public Shape {
public:
int getArea() { return (width * height) / 2; }
};
int main(void) {
Rectangle Rect;
Triangle Tri;
Rect.setWidth(5);
Rect.setHeight(7);
// 객체 면적 출력
cout << "Total Rectangle area: " << Rect.getArea() << endl;
Tri.setWidth(5);
Tri.setHeight(7);
// 객체 면적 출력
cout << "Total Triangle area: " << Tri.getArea() << endl;
return 0;
}
위 코드를 컴파일하고 실행하면:
Total Rectangle area: 35
Total Triangle area: 17
추상 클래스가 getArea() 측면에서 인터페이스를 정의하고, 두 다른 클래스가 같은 함수를 구현하지만 모양에 특화된 다른 알고리즘으로 면적을 계산하는 것을 볼 수 있습니다.
설계 전략
객체 지향 시스템은 모든 외부 애플리케이션에 적합한 공통되고 표준화된 인터페이스를 제공하기 위해 추상 기반 클래스를 사용할 수 있습니다. 그런 다음 그 추상 기반 클래스로부터 상속을 통해 유사하게 동작하는 파생 클래스들이 형성됩니다.
외부 애플리케이션이 제공하는 능력(즉, public 함수들)은 추상 기반 클래스에서 순수 가상 함수로 제공됩니다. 이 순수 가상 함수들의 구현은 애플리케이션의 특정 타입에 해당하는 파생 클래스들에서 제공됩니다.
이 아키텍처는 시스템이 정의된 후에도 새로운 애플리케이션을 시스템에 쉽게 추가할 수 있게 합니다.