Programming Language/C++

[C++] 순수 가상 함수와 추상 클래스

lumana 2024. 6. 27. 22:34

순수 가상 함수(pure virtual function)와 추상 클래스(abstract class)

  • 이전 시간까지 가상 함수에 대해서 배웠다.

    • 아래 예시와 같이 가상 함수를 통해 오버라이딩을 할 수 있었다.
#include <iostream>
using namespace std;

class A {  
   public:
    virtual void f() {}
};

class B : public A {
   public:
    void f() {}
};

int main() {
    A *a = new B;
    a->f();
    delete a;
}
  • 순수 가상 함수란 무엇인가요?

    • 가상이라는 것은 실제로는 존재하지 않는다는 의미인데, 이전 시간에서 다뤘듯 부모타입 포인터 변수가 부모타입 객체를 가리키면, 가상 함수 호출이 가능했다
    • 그래서 완전히 존재하지 않는 함수로 만들어 주기 위해, 순수 가상 함수를 사용한다.
class A {  // 추상클래스
   public:
         // 순수 가상함수
    virtual void f() = 0;  // 0 또는 NULL
};
  • 순수 가상 함수를 포함하고 있는 클래스는 그 타입을 갖는 인스턴스를 만들 수 없다.

    • 이러한 클래스를 추상 클래스라고 부른다
A *a = new A; // 에러 발생
  • 자식 인스턴스를 생성하는 것은 가능하다.
int main() {
        A *a = new B;
        a->f();
        delete a;
}

어떤 상황에서 순수 가상 함수를 사용하면 좋을까?

Example) 두 가지 도형 Circle, Rectangle이 있다고 해보자.

#include <iostream>

using namespace std;

const double PI = 3.1415;

class Circle {
   public:
    Circle(double r) : r(r) {}

    double GetArea() {
        return PI * r * r;
    }

    void Resize(double f) {
        r *= f;
    }

   private:
    double r;
};

class Rectangle {
   public:
    Rectangle(double a, double b) : a(a), b(b) {}

    double GetArea() {
        return a * b;
    }
    void Resize(double f) {
        a *= f;
        b *= f;
    }

   private:
    double a, b;
};
  • 두 클래스를 Shape라는 클래스에 한꺼번에 어딘가에 저장해주고 싶다.
Shape *shapes[] = {
        new Circle(10),
        new Rectangle(20, 30)
};
  • Shape라는 클래스로 뽑아내보자
class Shape {
   public:
    virtual double GetArea() {
                // 어떤 것을 리턴해야 할까?
        }
    virtual void Resize(double f) {
        }
};
  • 물론 shape의 GetArea()를 호출할 일은 없지만, 만약 실수를 해서 호출해버리게 된다면 virtual double GetArea()에서, 리턴해줄 것이 없다.

    • 이런 경우를 대비해서, 순수 가상 함수로 선언하여 추상 클래스로 만들어준다 --> 인스턴스를 만드는 것을 방지
class Shape {
   public:
    virtual double GetArea() = 0;
    virtual void Resize(double f) = 0;
};
  • 이제, 여러 개의 도형을 for문을 통해서 다뤄보자
int main() {
    Shape *shapes[] = {
        new Circle(10),
        new Rectangle(20, 30)};
    for (Shape *s : shapes) {
        s->Resize(2.0);
    }
    for (Shape *s : shapes) {
        cout << s->GetArea() << endl;
    }

    for (Shape *s : shapes) {
        delete s;
    }
}

참조) 두들낙서 C/C++ 강좌