내배캠/C++

가상 함수와 추상 클래스

동그래님 2024. 12. 24. 12:08

 

가상 함수와 추상 클래스에 대한 정리

 

 

1. 가상함수 (Virtual Function)

  • 선언: virtual void MakeSound( );
  • 자식 클래스에서 해당 함수의 세부 구현을 제공하면 자식 클래스의 함수가 호출된다.
  • 만약 자식클래스에서 구현하지 않았다면, 부모 클래스의 함수가 호출된다.
  • 가상 함수는 다형성을 구현하는 데 사용된다.
  • 다형성에서 부모클래스의 소멸자를 가상함수로 선언하지 않고 부모 클래스 포인터에서 자식 클래스의 소멸자를 호출하게 되면 부모 클래스의 소멸자만 호출되고 자식클래스의 소멸자는 호출되지 않아 메모리 누수가 발생할 수 있다.

- C++에서는 소멸자가 가상이 아니면, 정적 바인딩(static binding)으로 동작한다.

- 정적 바인딩은 컴파일 타임에 소멸자 호출이 결정되므로, 부모 클래스 포인터를 통해 객체를 삭제할 때, 해당 포인터가 가리키는 객체 타입은 부모 클래스로 간주된다.

 

2. 순수 가상 함수 (Pure Virtual Function)

  • 선언: virtual void MakeSound( ) = 0;
  • 순수 가상 함수는 함수의 구현 없이 선언만 존재한다.
  • 자식 클래스는 반드시 이 함수를 구현해야 한다. 그렇지 않으면 Error 발생.
  • 순수 가상 함수를 포함한 클래스는 추상 클래스가 된다.

 

3. 추상 클래스 (Abstract Class)

  • 추상 클래스는 순수 가상 함수를 하나 이상 포함한 클래스를 말한다.
  • 추상 클래스는 객체를 생성할 수 없다. (변수로 선언 불가)
  • 추상 클래스는 다른 클래스의 기반 클래스로 사용되어, 공통 기능을 정의하거나 자식 클래스가 반드시 구현해야 할 인터페이스를 제공하는 역할을 한다고 보면 된다.
// 부모 클래스: 추상 클래스
class Animal {
public:
    virtual void MakeSound() = 0; // 순수 가상 함수
    virtual void Move() {
        cout << "Animal moves!" << endl; // 일반 가상 함수
    }
};

// 자식 클래스: 추상 클래스의 구현
class Dog : public Animal {
public:
    void MakeSound() override {
        cout << "Dog barks!" << endl; // 순수 가상 함수 구현
    }
    void Move() override {
        cout << "Dog runs!" << endl; // 가상 함수 재정의
    }
};

int main() {
    // Animal animal; // 오류: 추상 클래스는 객체 생성 불가
    Dog dog;
    dog.MakeSound(); // 출력: Dog barks!
    dog.Move();      // 출력: Dog runs!

    Animal* ptr = &dog;
    ptr->MakeSound(); // 출력: Dog barks! (다형성)
    ptr->Move();      // 출력: Dog runs!
    return 0;
}

요약

  • virtual void MakeSound();
    • 가상 함수로, 자식 클래스에서 구현하지 않으면 부모 클래스의 함수가 호출됩니다.
    • 자식 클래스에서 구현하면 자식 클래스의 함수가 호출됩니다.
  • virtual void MakeSound() = 0;
    • 순수 가상 함수로, 반드시 자식 클래스에서 구현해야 합니다.
    • 이 함수가 포함된 클래스는 추상 클래스가 되며, 객체 생성이 불가능합니다.