가상 함수 테이블 (Virtual function table / vtable)
virtual 키워드를 사용해서 멤버 함수를 재정의할 경우 메모리에서 어떤 일이 일어나는지 가상 함수 테이블을 중심으로 살펴본다. 우선 아래와 같이 virtual을 사용하지 않은 경우를 살펴보자.
class Person
{
public:
void speak()
{
std::cout << "I'm Person" << std::endl;
}
private:
int ID;
};
class Student : public Person
{
public:
void speak()
{
std::cout << "I'm Student" << std::endl;
}
private:
int Student_ID;
};
int main()
{
Person * Tom = new Person();
Tom->speak();
Person * Jun = new Student();
Jun->speak();
std::cout << "Person: " << sizeof(Person) << " Student: " << sizeof(Student) << std::endl;
return 0;
}
I'm Person
I'm Person
Person: 4 Student: 8
출력 결과에서 두 가지 특징을 살펴볼 수 있다.
- Person* 타입의 Jun은 실제 Student의 인스턴스지만 Person의 speak() 함수를 사용한다.
- Person의 인스턴스의 크기는 4Byte (ID)이고, Student의 인스턴스 크기는 8byte(ID, Student_ID)이다.
(이글에서 테스트는 32bit 기준으로 진행한다. 64bit에서는 다른 결과가 나올 것이다.)
Person과 Student 인스턴트의 구조를 살펴보면 다음과 같을 것이다.
이번에는 speak 함수를 다음과 같이 가상 함수(virtual)로 선언해보자.
class Person
{
public:
virtual void speak()
{
std::cout << "I'm Person" << std::endl;
}
private:
int ID;
};
class Student : public Person
{
public:
void speak() override
{
std::cout << "I'm Student" << std::endl;
}
private:
int sID;
};
int main()
{
Person * Tom = new Person();
Tom->speak();
Person * Jun = new Student();
Jun->speak();
std::cout << "Person: " << sizeof(Person) << " Student: " << sizeof(Student) << std::endl;
return 0;
}
I'm Person
I'm Student
Person: 8 Student: 12
여기서 두 가지 특징을 살펴보자.
- Person* 타입의 Jun이 실형식 Student의 speak() 함수를 호출했다.
- Person과 student의 객체 크기가 4byte씩 증가하였다.
첫 번째 특징에서 우리는 다형성(Polymorphism)을 확인할 수 있다. 그리고 추가로 멤버 변수를 선언하지도 않았는데 객체의 크기가 4byte만큼 증가한 것을 확인할 수 있다. 이 4byte는 가상 함수 테이블을 가리킬 포인터에 해당한다.
virtual 키워드를 사용하여서 가상 함수를 만들게 되면 컴파일러는 가상 함수 테이블(Virtual Function Table / vftable)을 만든다. 그리고 가상 함수를 가지는 클래스의 객체에는 어느 가상 함수를 참조할지 정하는 가상 함수 포인터(Virtual Function Pointer / vfptr)를 만든다. 이 가상 함수 포인터(vfptr) 때문에 객체의 크기가 4byte 증가한 것이다. 그리고 이 가상 함수 포인터를 활용하여 컴파일러는 생성되는 인스턴스의 형식에 따라서 어느 가상 함수 테이블을 참조할지를 정하게 된다.
이상 가상 함수 테이블에 대해서 알아보았다.
참조:
유튜브 채널 - 코드없는 프로그래밍: https://www.youtube.com/channel/UCHcG02L6TSS-StkSbqVy6Fg