갬장장이
Virtual 키워드의 세부적인 작동 원리 - 함수 포인터와 Vtable
갬장장이
갬장장이의 코드 대장간
갬장장이
전체
오늘
어제
  • 분류 전체보기 (216)
    • 게임 연구소 (6)
    • 게임 제작 (15)
      • We need more guns (2024~) (1)
      • Rovenhell (2023) (2)
      • Geophyte (2020~2021) (5)
      • 아드레날린 러시 (2021) (2)
      • Treadmill (2019) (1)
      • 습작들 (2019~) (2)
      • 그 외 (~2018) (2)
    • mathematics (33)
      • game mathematics (30)
      • linear algebra (3)
    • networking (3)
    • computer graphics (46)
      • 3D Graphics (23)
      • DirectX (8)
      • OpenGL (13)
      • graphics theory (2)
    • game engines (10)
      • Unity (0)
      • Unreal Engine (10)
    • os (6)
      • Linux (0)
      • operating system (1)
      • multithreading, parallel co.. (5)
    • lang (34)
      • c++ (15)
      • .NET (5)
      • python (1)
      • java (3)
      • erlang, elixir (1)
      • js, ts (7)
    • software engineering (47)
      • PS (25)
      • algorithms (15)
      • data structures (2)
      • design patterns (4)
    • cs (4)
    • database (2)
      • SQL (1)
    • web (6)
      • web (3)
      • frameworks, libraries (3)
    • finance (0)
    • 음악 제작 (1)
    • life (3)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

  • [공지] 블로그 안내

인기 글

최근 댓글

최근 글

hELLO · Designed By 정상우.
lang/c++

Virtual 키워드의 세부적인 작동 원리 - 함수 포인터와 Vtable

2021. 1. 1. 07:51
목차
  1. 함수 포인터란?
  2. Vtable이란?

함수 포인터란?

말 그대로 함수를 가리키는 포인터이다.

코드를 통해 사용방법을 설명하겠다.

void PrintNumber(int n)
{
	std::cout << n << std::endl;
}

auto f1 = PrintNumber;
f1(); // 가능

auto f2 = PrintNumber();
f2(); // 불가능

void(*f3)(int);
f3 = PrintNumber;
f3(); // 가능

void(*f4)(int) = PrintNumber;
f4(); // 가능

typedef void(*PrintNumberFunc)(int);
PrintNumberFunc f5 = PrintNumber;
f5(); // 가능

 

Vtable이란?

Virtual function table의 줄임말로, 쉽게 설명하면 함수 포인터들이 담긴 배열이다.

Vtable은 virtual 키워드가 정상적으로 작동할 수 있게 해준다.

 

코드에서 명시적으로 표시해주지는 않지만, 각 클래스의 생성자가 실행될 때

Vtable값을 가리키는 포인터 변수가 같이 생성된다고 생각하면 편하다.

 

이 때 중요한 점은, 만약 다른 클래스를 상속받은 자식클래스라면

상속 관계의 생성자 호출 및 처리 순서에 따라 Vtable의 값도 변한다는 점이다.

 

예시와 함께 설명해보겠다.

Fruit 클래스와, 이 클래스를 상속받은 Apple 클래스가 있다고 가정하자.

또 Fruit는 virtual void Hello() { std::cout << "Fruit hello"; } 라는 함수를 가지고 있으며

Apple은 이 함수를 오바라이딩한 virtual void Hello() { std::cout << "Apple hello"; }라는 함수를 가지고 있다고 하자.

 

Apple 클래스의 인스턴스를 동적으로 생성하고, 생성된 개체를 Fruit 타입 포인터 apple로 저장했다고 가정하자.

Fruit* apple = new Apple;

 

이때 apple->Hello()를 실행하면 virtual 키워드의 성질에 의해 "Apple hello"가 출력된다.

 

 

그렇다면 어떻게 virtual 키워드는 다른 타입 포인터임에도 오버라이딩한 메소드를 찾아 사용할까?

그 원리는 Vtable에서 찾을 수 있다.

 

앞서 제시한 예시대로 코드를 작성해 실행하면 다음 순서로 진행된다.

Apple() 호출

Fruit() 호출

Fruit() 실행

Apple() 실행

 

이때 중요한 점은 생성자가 실행될 때마다 그 클래스의 Vtable을 값도 새로 초기화된다는 것이다.

virtual 함수를 가지고 있는 클래스 내부에는 __vfptr이라는 이름의 vtable을 가리키는 포인터 변수가 저장되어있는데,

이 포인터 변수는 클래스 생성자가 실행될 때 그 클래스 내부의 함수들을 저장하는 Vtable을 가리키도록 초기화된다.

 

즉, 위 과정에서는 사실 다음과 같은 일들이 벌어지는 셈이다.

Apple() 호출

Fruit() 호출

Fruit() 실행

--> Vtable 값에는 Fruit::Hello()를 가리키는 함수 포인터가 저장된다. 그리고 *apple->__vfptr은 이 Vtable을 가리킨다.

Apple() 실행

--> Vtable 값에는 Apple::Hello()를 가리키는 함수 포인터가 저장된다. 그리고 *apple->__vfptr은 기존에 가리키던 Vtable 대신 새로 생긴 Vtable을 가리킨다.

 

이러한 과정을 거친 후 apple->Hello()를 실행하면 Vtable에 저장된 데이터를 통해 우리가 실행해야 하는 함수가 Apple::Hello()라는 것을 알 수 있고, 덕분에 virtual 키워드가 정상적으로 작동하게 되는 것이다.

저작자표시 비영리 변경금지

'lang > c++' 카테고리의 다른 글

std::set의 iteration  (0) 2021.03.30
동적 바인딩 혹은 늦은 바인딩이란(Dynamic binding)  (0) 2021.01.01
STL Set의 메모리 구조  (0) 2020.12.22
STL Vector에 클래스를 저장할 때 발생하는 일들  (0) 2020.12.22
STL Vector의 메모리 구조  (0) 2020.12.22
  • 함수 포인터란?
  • Vtable이란?
'lang/c++' 카테고리의 다른 글
  • std::set의 iteration
  • 동적 바인딩 혹은 늦은 바인딩이란(Dynamic binding)
  • STL Set의 메모리 구조
  • STL Vector에 클래스를 저장할 때 발생하는 일들
갬장장이
갬장장이
상단으로

티스토리툴바

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.