본문 바로가기
프로그래밍 언어/C++

[C++] 가상함수 테이블

by 까망 하르방 2025. 3. 6.
반응형

가상 함수 테이블(vtable) 개념

가상함수는 실행시간에 어떻게 타입을 조사할까?
실행시간에 해당 함수 호출하려면 함수 주소를 알아야 한다.

C++ 컴파일러는 가상 함수 테이블(vtable) 을 생성하여
런타임에 올바른 함수를 찾는다.

** 가상함수 원리는 컴파일러 종류와 버전에 따라 다를 수 있다.

#include <iostream>
using namespace std;

class Base
{
    int d;
public:
    virtual void f1() {}
    virtual void f2() {}
    virtual void f3() {}
};

class Derived : public Base
{
    int d;
public:
    virtual void f2() override {}
};

int main()
{
    Base    b1, b2;
}



• 클래스에 하나 이상의 가상 함수가 있으면
• 컴파일러는 해당 클래스의 vtable 생성
• 각 클래스의 vtable에는 가상 함수들의 주소 저장
• 객체에는 vtable을 가리키는 포인터(vptr)가 숨겨진 멤버로 포함

#include <iostream>
using namespace std;

class Base
{
    int d;
public:
    virtual void f1() {}
    virtual void f2() {}
    virtual void f3() {}
};

class Derived : public Base
{
    int d;
public:
    virtual void f2() override {}
};

int main()
{
    Derived d1;

    Base* p = &d1;
    p->f2(); // p->ptrtable[2]()
}



가상 함수를 호출할 때
vptr 통해 vtable에서 해당 함수의 주소 찾아 실행.


→ 가상함수가 선언된 순서를 가지고 검색
 ex) "p->f2()" 는 2번째 선언된 가상함수로
   테이블에서 2번째 항목을 주소로 꺼내 호출

• 가상 함수 호출 시 주소를 꺼내서 호출하므로 overhead 발생
 → 인라인 치환 될 수 없음


• 클래스마다 하나의 vtable이 생성되고
 객체마다 vptr 포인터(보통 8바이트)가 추가기에
 많은 객체를 생성할 경우 vptr 포인터가 차지하는 메모리가 누적될 수 있음

#include <iostream>
using namespace std;

class Base
{
    int d;
public:
    virtual void f1() {}
    virtual void f2() {}
    virtual void f3() {}
};

class Derived : public Base
{
    int d;
public:
    virtual void f2() override {}
};

int main()
{
    Base    b1, b2;
    Derived d1;

    Base* p = &d1;
    p->f2(); // p->ptrtable[2]()
}



실제 객체 크기를 확인해보면
멤버변수 외 가상함수 포인터 포함하고 있는 것을 확인할 수 있다.
memory align 이나 컴파일러에 따라 결과 다를 수 있음

#include <iostream>
using namespace std;

class Base
{
    int d;
public:
    virtual void f1() {}
    virtual void f2() {}
    virtual void f3() {}
};

class Derived : public Base
{
    int d;
public:
    virtual void f2() override {}
};

int main()
{
    Base    b1;
    Derived d1;

    cout << sizeof(b1) << endl;
    cout << sizeof(d1) << endl;
}



Base = "8B" + 8B
Derived = "8B" + 8B + 8B


📌 [C++] 인라인(inline) 함수

 

[C++] 인라인(inline) 함수

키워드 「inline」 로 정의된 함수를 "인라인 함수"라 한다. 보통, 구조가 간단한 함수를 inline 처리해야 효율성을 높일 수 있다. inline void Add(int a, int b) { return a + b; } 클래스 또는 구조체 안에 멤버

zoosso.tistory.com

 

📌 [C++] 가상 함수 (virtual funciton)

 

[C++] 가상 함수 (virtual funciton)

가상 멤버 함수 (virtual function)동적 바인딩을 위해 사용class A{public: virtual void sub(void);};  [예제] 함수 재정의(overriding) 주의사항#include class Animal{public: void Cry() { std::cout Cry(); // ??? -> Dog? Animal?}Q) p-

zoosso.tistory.com

 

📌 [C++] 가상 소멸자

 

[C++] 가상 소멸자

가상 소멸자 C++에서는 가상 함수(virtual)가 하나라도 있는 클래스라면 소멸자도 virtual로 만드는 것이 안전한 습관이다. [예제] 부모-자식 객체 생성자/소멸자 순서 #include using namespace std;clas

zoosso.tistory.com

반응형

댓글