C++ <가상 함수의 동작 원리>
V-Table & V-Pointer
가상 함수의 동작 원리를 이해하기 위해 꼭 필요한 개념인 V-Table와 V-Pointer에 대해 먼저 알아봅시다.
V-Table 란?
- 하나 이상의 가상 함수를 가진 클래스에 대해서 컴파일러에서 만들며 바이너리 'rdata' 영역에 기록되는 테이블
- Key 와 Value 로 구성되어 있으며 Key 를 통해 Value 에 접근하는 방식으로 Key 에는 함수 식별자, Value 에는 함수의 주소 정보가 저장됨.
V-Pointer 란?
- V-Table 의 주소를 참조하는 포인터 변수로 가상 함수를 가진 클래스로 객체를 생성했을 때 그 생성된 각각의 객체가 V-Pointer 를 갖고있음.
V-Table 생성 원리
AAA 라는 클래스가 존재하고 BBB 클래스가 이를 상속받는 상황을 생각해봅시다.
class AAA
{
private:
int num1;
public:
virtual void Func1() { cout << "Func1" << endl; }
virtual void Func2() { cout << "Func2" << endl; }
};
먼저 AAA 클래스에는 가상함수로 Func1, Func2 가 존재합니다. 그렇다면 컴파일러에 의해 다음과 같이 V-Table 이 만들어집니다.
AAA 클래스를 상속받는 BBB 클래스를 정의합니다.
class BBB : public AAA
{
private:
int num2;
public:
virtual void Func1() { cout << "BBB::Func1" << endl; }
void Func3() { cout << "Func3" << endl; };
};
여기서 중요하게 살펴보야할 점은 BBB 클래스의 V-Table 에는 AAA::Func1 함수의 정보가 없다는 것입니다.
이처럼 함수가 오버라이딩 되는 경우에는 자식 클래스의 V-Table 에 오버라이딩 된 함수의 정보만 담게되므로 자식 클래스를 통해 오버라이딩 된 함수를 실행하면 무조건 가장 마지막에 오버라이딩을 한 자식 클래스의 멤버 함수가 호출됩니다.
V-Pointer
위 V-Table 생성 원리를 통해 V-Pointer 를 이해해 봅시다.
AAA 클래스로 객체를 만들게 되면 그 객체는 AAA 클래스의 V-Table 의 주소를 갖는 V-Pointer 변수를 갖습니다.
BBB 클래스도 마찬가지로 객체를 만들게 되면 BBB 클래스의 V-Table 주소를 갖는 V-Pointer 변수를 갖습니다.
따라서 클래스 내부에 멤버 함수는 객체 내부에 있지 않습니다.
또한 한 클래스로 만든 여러 객체는 각각의 멤버 함수 V-Table 을 가지지 않고 하나의 V-Table 을 객체들이 공유하는 형태로 작동합니다.