[C++] 10 가상함수(Virtual function)

김진우·2025년 5월 21일

C++

목록 보기
10/16
post-thumbnail

정의

자식 클래스에서 함수를 재정의(override) 할 수 있도록 부모가 허락한 함수이다.

virtual키워드를 사용해 override될 함수를 가상 함수로 사용할 수 있다.

class Parent {
public:
    virtual void hello() {
        std::cout << "Hello from Parent\n";
    }
};

class Child : public Parent {
public:
    void hello() override {
        std::cout << "Hello from Child\n";
    }
};

virtual 없으면 → 자식이 hello() 만들면 그냥 자기 함수 하나 만든 것이다. (부모 함수는 그대로 있다.)
virtual 있으면 → 자식이 hello() 만들면 부모의 함수를 덮어쓴다.(override)

override를 한 함수에서는 override키워드를 붙여 정확하게 덮어 쓴다는걸 명시한다.

Virtual Table(가상 함수 테이블)

C++은 객체가 가상 함수를 가지면, Virtual Table을 생성해 가상 함수의 주소를 저장한다.
객체마다 자기 클래스의 Virtual Table을 가리키는 vptr (virtual pointer)를 내부에 하나 가져서 가상 함수에 접근하게 된다.

Dog d;           // Dog 객체
Animal* a = &d;  // 부모 포인터로 자식 객체 가리킴
a->speak();      // V-Table 통해 실제 Dog::speak 주소 호출

virtual 있을 때 흐름:
1. a->speak() 호출한다.
2. a는 vptr을 통해 V-Table 접근한다.
3. V-Table에서 speak() 함수 주소를 가져온다.
4. 해당 주소로 Dog::speak() 실행한다.

만약 virtual이 없다면 함수 주소는 프로그램 실행 시 결정되어서 객체의 실제 타입과 관계없이 포인터의 타입 기준으로 호출이 된다.

순수 가상함수

부모 클래스에서 내용을 정의 하지 않은 가상 함수를 순수 가상함수라고 한다.
즉, 부모 클래스에서는 함수 내용이 없어서 사용할 수 없고 자식 클래스에서 overriding 해서 사용해야 한다.

함수 선언 뒤에 = 0키워드를 붙여 순수 가상함수로 사용 가능하다.

class Animal {
public:
    virtual void name() = 0;  // 이름만 있고 몸통 없음 = 추상
};

class Dog : public Animal {
public:
    void name() override {
        std::cout << "Dog\n";
    }
};

자식 클래스에서 이 함수를 안만들면 컴파일 에러가 발생한다.

추상 클래스

순수 가상함수가 하나라도 있는 클래스를 추상 클래스라고 한다.
추상 클래스는 객체를 만들 수 없다. 즉, 클래스를 만드는 틀을 정의한다고 생각하면 된다.

Animal a; // 선언 불가 (추상 클래스는 객체 못 만든다.)
Dog d; // 선언 가능
Animal* a = new Dog(); // 선언 가능 (업캐스팅)

a->name(); // Dog의 name()함수 실행

업 캐스팅을 통해 선언이 될 경우 vptr → V-Table → Dog::name()으로 접근되어서 override된 함수가 실행된다.

왜 사용할까?

서로 공통되는 기능을 통일된 인터페이스로 만들어 다형성을 구현하기 위해 사용된다.

공통된 부모 타입을 통해 여러 자식 클래스를 동일한 방식으로 처리할 수 있고, 객체가 늘어나도 코드 수정 없이 확장이 가능해진다.

즉, virtual은 어떤 객체든 자식 함수가 실행되게 하고, abstract class는 자식이 무조건 구현해야 하게 해서 "유지보수가 쉬운, 유연하고 확장 가능한 코드"를 만들기 위한 도구이다.

0개의 댓글