class Shape {
public:
bool bValid;
public:
virtual double GetArea() const = 0;
};
→ return 타입이 double이고, parameter는 없으며 const 타입의 virtual 함수 GetArea를 선언한다. 이때 = 0;을 통해 이 함수가 순수가상함수임을 명시하여, 해당 클래스가 추상 클래스가 되도록 한다.
함수 뒤에 = 0을 붙이면 순수가상함수이다. 함수의 구현(본문)은 없고, 선언만 한다. 이 함수는 자식 클래스가 반드시 override(재정의) 해야 한다. 만약 자식 클래스가 이 함수를 구현하지 않으면, 그 자식 클래스도 추상 클래스가 된다.
하나 이상의 순수가상함수를 포함하는 클래스는 추상 클래스가 된다. 추상 클래스는 instance를 만들 수 없다. 공통된 인터페이스만 정의하고, 구체적인 구현은 파생 클래스가 한다. interface 역할(틀, 계약)을 하며, 자식 클래스에게 특정 함수 구현을 강제한다.
| 구분 | 설명 |
|---|---|
| 순수가상함수 | virtual 함수명() = 0 형태로, 반드시 자식 클래스가 구현해야 함 |
| 추상 클래스 | 하나 이상의 순수가상함수를 가진 클래스 (객체 생성 불가) |
| 목적 | 자식 클래스에게 함수 구현을 강제하고, 다형성을 지원함 |
| 사용 예 | 도형 클래스(Shape)는 GetArea()를 구현하지 않지만, 자식 클래스인 Rectangle, Triangle 등에서 각각 다르게 구현 |
class Shape {
public:
virtual double GetArea() const = 0; // 순수가상함수 → Shape는 추상 클래스
};
class Rectangle : public Shape {
double width, height;
public:
Rectangle(double w, double h) : width(w), height(h) {}
double GetArea() const override { return width * height; }
};
int main() {
// Shape s; // ❌ 오류: 추상 클래스는 객체 생성 불가
Rectangle r(3, 4);
Shape& s = r; // ✅ 업캐스팅
std::cout << s.GetArea(); // 12 출력
}
겉보기엔 Shape 클래스는 아무 기능도 없고 직접 객체도 못 만드니까 "왜 만들지?" 하는 의문이 든다. 하지만 Shape class는 매우 중요한 역할을 한다.
| 이유 | 설명 |
|---|---|
| 1. 공통 인터페이스 제공 | 모든 도형(Rectangle, Triangle 등)이 반드시 GetArea()를 갖도록 강제 |
| 2. 다형성(Polymorphism) 지원 | Shape* 또는 Shape& 타입 하나로 다양한 도형을 처리 가능 |
| 3. 확장성 있는 설계 | 새로운 도형(예: Circle, Polygon 등)을 쉽게 추가 가능 |
| 4. 코드 재사용과 일관성 | 같은 방식으로 모든 도형의 넓이를 계산하거나 처리 가능 |
Shape 클래스는 비록 직접 쓸 수는 없지만, 모든 도형의 '틀'을 정의하고,통일된 방식으로 처리하기 위한 핵심 역할을 한다.
👉 Shape는 "도형이라는 개념을 설계적으로 통합"하는 데 꼭 필요한 Abstract Interface class다.
Shape* 또는 Shape& 타입으로 다양한 도형을 처리할 수 있다?
부모 클래스 포인터(Shape*)나 참조(Shape&)를 통해 자식 클래스의 오버라이드된 함수를 호출하는 기능입니다.
이 기능 덕분에 Rectangle, Triangle, Circle 등 다양한 도형을
한 가지 타입(Shape)으로 통합해서 처리할 수 있습니다.
Shape* pShape1 = new Rectangle(3, 4); // 사각형 객체를 Shape 포인터로 저장
Shape* pShape2 = new Triangle(3, 4, 5); // 삼각형 객체도 Shape 포인터로 저장
std::cout << pShape1->GetArea() << std::endl; // Rectangle의 GetArea 호출
std::cout << pShape2->GetArea() << std::endl; // Triangle의 GetArea 호출
→ pShape1과 pShape2는 모두 Shape* 타입이지만, 실제로는 각각 Rectangle과 Triangle 객체를 가리키고 있으므로 자식 클래스의 GetArea() 함수가 실행된다.
이게 바로 다형성입니다.
void PrintArea(Shape& s) {
std::cout << s.GetArea() << std::endl;
}
Rectangle r(3, 4);
Triangle t(3, 4, 5);
PrintArea(r); // Rectangle의 GetArea() 실행
PrintArea(t); // Triangle의 GetArea() 실행
→이 경우는 포인터 대신 참조(&)를 사용했을 뿐이고, 동작은 똑같이 자식 클래스의 GetArea()가 실행됩니다.