애드센스 728x90


가상함수 테이블 C플러스플러스

[출처] 클래스 단위로 컴파일러가 생성하는 가상함수 테이블|작성자 동키


C++ 컴파일러는 가상 함수를 호출할때 자료형을 참조하는 것이 아니라, 객체 포인터를 이용해 함수를 호출하게 되는데, 이를 구현하기 위해 C++ 컴파일러는 컴파일 단계에서 가상 함수를 가지는 모든 클래스에 대해 가상 함수 테이블을 생성한다. 이 가상 함수 테이블 내의 각 항목은 정의된 가상 함수를 가리킨다. C++ 컴파일러는 가상 함수를 가지는 클래스의 객체에 대해 객체가 할당된 메모리의 처음 4바이트에 가상 함수 테이블의 주소를 저장한다..

 

가상함수 테이블 포인터(vptr)을 이용해 가상함수를 호출하기 때문에 객체의 처음 4바이트가 어떤 클래스의 가상 함수 테이블을 가리키는지에 따라 다른 가상 함수를 테이블이 구체적으로 어떻게 생성되고 객체는 자신의 처음 4바이트를 어떻게 초기화시키는지 알아보자

 

가상 함수 테이블이 클래스 단위로 생성된다고 했는데, C++ 컴파일러가 가상함수 테이블을 클래스 단위로 생성하는 것은 객체의 메모리 크기를 줄이기 위해서 이다. 만약 객체 메모리 영역에 직접 가상 함수 포인터를 생성한다면 가상 함수 개수에 비례하여 객체의 크기는 늘어날 것이다.

어차피 동일한 클래스로 생성된 객체들은 동일 가상 함수를 호출해야 하기 때문에 이것은 메모리 낭비가 아닐수 없다.

 

그래서 C++ 컴파일러는 가상함수를 가리키는 포인터를 테이블로 구성하고 이것을 클래스 단위로 생성한 다음 이 테이블에 대한 포인터를 객체 맨 앞에 4바이트에 설정함으로서 간단하게 객체에 가상함수 테이블을 포함하는 효과를 가질수 있도록 한다. 이렇게 C++ 컴파일러가 가상함수 테이블을 관리하기 때문에 가상함수를 가지는 클래스는 가상함수의 개수에 상관없이 객체의 크기는 항상 멤버 변수의 총 크기에 4바이트를 더한 크기로 생성될수 있게 된다.

 

가상 함수에 대한 모든 원리는 테이블과 관련이 있기 때문에 이것에 대해 좀더 알아보자

가상 함수 테이블의 크기는 해당 클래스에 정의된 가상함수 개수에 비례한다.

여기서 정의된 가상함수란 상위 클래스에 정의된 가상함수도 포함한다.

그래서 상위 클래스에 두개의 가상함수가 정의되고, 자신의 클래스에 하나의 가상 함수가 정의 된다면 가상 함수 테이블 내의 항목은 상위 클래스의 가상 함수를 가리킨다. 너무나 당연한 이야기지만 가상 함수 테이블 내의 항목은 재정의 된 가상 함수를 가리킨다. 가상 함수 테이블의 이런 특징 때문에 어떤 클래스가 가상 함수를 상속 받아 가상 함수를 재정의 하지 않고 객체를 생성하여 해당 가상 함수를 호출하면 상위 클래스에 정의된 가상 함수가 호출된다. 


덧글

댓글 입력 영역