C++ 초급 - 8. 객체지향 프로그래밍 (3 - 순수 가상 함수 (= 0))

2025. 2. 22. 15:40프로그래밍 언어/C++

📌 8.3 순수 가상 함수 (= 0)

C++에서 순수 가상 함수(Pure Virtual Function)자식 클래스에서 반드시 구현해야 하는 가상 함수를 의미한다.
이를 포함하는 클래스를 추상 클래스(Abstract Class)라고 하며, 추상 클래스는 직접 인스턴스를 생성할 수 없고, 인터페이스 역할을 한다.


📌 1. 순수 가상 함수란? (virtual 함수명() = 0;)

🔹 (1) 순수 가상 함수 정의

  • 순수 가상 함수(Pure Virtual Function)= 0을 사용하여 선언하는 함수.
  • 구현 없이 선언만 존재하며,
    해당 클래스를 상속받은 자식 클래스에서 반드시 오버라이딩해야 함.

💡 기본 문법

class 클래스이름 {
public:
    virtual void 함수명() = 0;  // 순수 가상 함수 선언
};

💡 예제: 순수 가상 함수 선언

class Animal {
public:
    virtual void makeSound() = 0;  // 순수 가상 함수 (추상 클래스)
};
  • makeSound()는 구현 없이 선언만 되어 있으며, = 0을 사용하여 순수 가상 함수로 정의됨.
  • 이를 상속받는 자식 클래스에서 반드시 오버라이딩하여 구현해야 함.

📌 2. 추상 클래스(Abstract Class)의 역할

🔹 (1) 추상 클래스란?

  • 순수 가상 함수를 하나 이상 포함하는 클래스추상 클래스(Abstract Class)라고 함.
  • 추상 클래스는 직접 객체(인스턴스) 생성이 불가능하며, 반드시 상속을 통해 기능을 확장하여 사용해야 함.
  • 인터페이스(Interface) 역할을 수행하며, 자식 클래스가 특정 기능을 구현하도록 강제함.

💡 예제: 추상 클래스 사용

#include <iostream>

// 추상 클래스 (순수 가상 함수 포함)
class Animal {
public:
    virtual void makeSound() = 0;  // 순수 가상 함수 (자식 클래스에서 반드시 구현해야 함)
};

// 구체적인 클래스 (추상 클래스를 상속받아 구현)
class Dog : public Animal {
public:
    void makeSound() override { std::cout << "멍멍!" << std::endl; }
};

class Cat : public Animal {
public:
    void makeSound() override { std::cout << "야옹!" << std::endl; }
};

int main() {
    // Animal a;  // ❌ 오류! (추상 클래스는 직접 인스턴스 생성 불가)
    
    Animal* dog = new Dog();
    Animal* cat = new Cat();

    dog->makeSound();  // ✅ "멍멍!"
    cat->makeSound();  // ✅ "야옹!"

    delete dog;
    delete cat;
    return 0;
}

🔹 출력 결과

멍멍!
야옹!

💡 설명

  • Animal 클래스는 makeSound()를 순수 가상 함수로 선언추상 클래스가 됨.
  • Dog와 Cat 클래스는 makeSound()를 반드시 오버라이딩하여 구현.
  • Animal* dog = new Dog(); → 부모 클래스 포인터를 사용하여 다형성 활용 가능.
  • Animal a; → 컴파일 에러 발생 (추상 클래스의 인스턴스 생성 불가).

📌 3. 순수 가상 함수의 구현 방식

🔹 (1) 자식 클래스에서 반드시 override하여 구현해야 함

  • 순수 가상 함수가 선언된 부모 클래스를 상속받는 경우, 자식 클래스에서 반드시 오버라이딩해야 함.
  • 자식 클래스가 해당 함수를 오버라이딩하지 않으면, 자식 클래스도 추상 클래스가 됨.

💡 예제: 순수 가상 함수를 오버라이딩하지 않은 경우

class Bird : public Animal {
    // makeSound()를 오버라이딩하지 않으면 Bird도 추상 클래스가 되어 객체 생성 불가
};

🔹 결과

컴파일 오류 발생! (Bird 클래스도 추상 클래스가 됨)

💡 올바른 방법

class Bird : public Animal {
public:
    void makeSound() override { std::cout << "짹짹!" << std::endl; }
};

📌 4. 가상 함수 테이블(Virtual Table, V-Table)과 다형성 원리

🔹 (1) 가상 함수 테이블(V-Table)이란?

  • C++에서 가상 함수를 사용하는 경우, 객체는 가상 함수 테이블(Virtual Table, V-Table)을 가짐.
  • V-Table은 클래스의 가상 함수 포인터를 저장하는 테이블로, 객체가 호출해야 할 가상 함수를 런타임에 동적으로 결정한다.

🔹 (2) V-Table을 활용한 다형성 원리

  • 일반 함수 호출: 컴파일 타임(정적 바인딩)에서 결정됨.
  • 가상 함수 호출: V-Table을 통해 런타임(동적 바인딩)에서 결정됨.

💡 예제: 가상 함수 테이블을 활용한 다형성

#include <iostream>

class Base {
public:
    virtual void show() { std::cout << "Base 클래스" << std::endl; }
};

class Derived : public Base {
public:
    void show() override { std::cout << "Derived 클래스" << std::endl; }
};

int main() {
    Base* ptr = new Derived();  // 부모 클래스 포인터로 자식 객체 생성
    ptr->show();  // ✅ Derived 클래스의 함수가 호출됨 (V-Table을 통한 동적 바인딩)

    delete ptr;
    return 0;
}

🔹 출력 결과

Derived 클래스

💡 설명

  • 컴파일 타임에는 Base의 show()가 호출될 것처럼 보이지만,
    V-Table을 활용하여 런타임에 Derived의 show()가 실행됨 (동적 바인딩 적용).

📌 5. 정리

개념 설명
순수 가상 함수 virtual 함수명() = 0; 형태로 선언되며, 자식 클래스에서 반드시 구현해야 함
추상 클래스 순수 가상 함수를 하나 이상 포함하는 클래스 (인스턴스 생성 불가)
인터페이스 역할 추상 클래스는 인터페이스 역할을 수행하며, 특정 기능을 자식 클래스에서 강제 구현하도록 함
오버라이딩 필수 순수 가상 함수를 오버라이딩하지 않으면 자식 클래스도 추상 클래스가 됨
가상 함수 테이블(V-Table) 런타임에 동적으로 함수를 결정하는 테이블, 다형성의 핵심 원리