Qaupot Blog
Software Engineering, Trip

408. 가상 함수 테이블

🕐 Sun, 23 Apr 2017 09:00:00 GMT

가상 함수 테이블 (Virtual function table)

가상 함수 테이블은 가상 함수에 대해 연결되어 있는 함수 포인터를 저장하는 공간입니다. 기본적인 원리는 다음과 같습니다.

  1. 클래스 내에 가상 함수가 존재하는지 확인합니다.
  2. 클래스 내에 가상 함수가 있다면, 가상 함수 테이블을 생성합니다. 그리고 이 테이블의 포인터를 인스턴스의 가장 앞 혹은 뒤에 항상 추가합니다.
  3. 가상 함수를 호출할 때, 위의 테이블을 참조하여 실제 호출될 함수를 찾습니다.

아래의 예제는 vtable로 부터 함수를 찾아 호출하는 예제입니다. 시스템에 따라 동작하지 않거나 크래시가 발생할 수 있습니다.


#include <iostream>

class Person
{
public:
    void DoAction()
    {
        Action();
        void (*actionPtr)() = (void (*)())(**(void***)this); // from vtable.
        
        actionPtr();
    }
private:
    virtual void Action() = 0;
};

class Student : public Person
{
private:
    virtual void Action()
    {
        std::cout << "Study" << std::endl;
    }
};

class Employee : public Person
{
private:
    virtual void Action()
    {
        std::cout << "Work" << std::endl;
    }
};

int main(int argc, char** argv)
{
    Student student;
    Employee employee;
    
    student.DoAction();
    std::cout << std::endl;
    employee.DoAction();
}

Study
Study

Work
Work

  1. 우선 Instance의 가장 처음 혹은 끝에 '가상 함수 테이블'에 대한 포인터가 존재하므로

this 포인터를 void***으로 캐스팅 합니다. (다른 멤버 변수가 없으므로)

  1. void***(가상 함수 테이블의 주소를 담는 포인터 == this)에 포인터 연산 1회로 '가상 함수 테이블'의 주소를 얻습니다.

  2. void** (실제 연결된 함수의 주소를 담는 포인터 == 가상 함수 테이블)에서 포인터 연산 1회로 '실제 연결되어 있는 함수'의 주소를 얻습니다.

가상 함수 테이블은 실제 연결되어 있는 여러 함수 들을 Array처럼 보관합니다.

  1. void* (실제 연결되어 있는 함수의 주소를 담는 포인터)을 void (*)() (함수 포인터)로 캐스팅합니다.

  2. 함수 포인터를 호출하면, 알맞는 가상 함수가 호출됩니다.

위에서 확인 가능한 것 처럼, 가상 함수를 사용하면 '컴파일러가 임의의 데이터를 덧 붙이는 과정'이 있습니다. C style의 메모리 동적할당 (malloc)을 이용해서 메모리를 할당 하고, 이를 클래스로 캐스팅 해서 사용하는 경우 가상 함수 테이블에 대한 연결이 없기 때문에 문제를 일으킬 수 있습니다.

이 블로그는 개인 블로그입니다. 게시글은 오류를 포함하고 있을 수 있지만, 저자는 오류를 해결하기 위해 노력하고 있습니다.
게시글에 별도의 고지가 없는 경우, 크리에이티브 커먼즈 저작자표시-비영리-변경금지 4.0 라이선스를 따릅니다.

This blog is personal blog. published posts may contain some errors, but author doing efforts to clear errors.
If post have not notice of license, it under creative commons Attribution-NonCommercial-NoDerivatives 4.0.