(C++)가상함수(Virtual Function)

■ 가상 함수의 실체

객체 안에는 실제로 멤버함수가 존재하지 않는다. 실제로 C++의 객체와 멤버함수는 함수를 공유하는 구조를 가진다.
객체가 생성되면 멤버변수는 객체 내에 존재하지만, 멤버함수는 메모리의 한 공간에 별도로 위치하고선, 이 함수가
정의된 클래스의 모든 객체가 이를 공유하는 형태를 취한다.

virtual로 선언된 가상함수를 하나이상 포함하는 클래스에 대해서는 컴파일러가 '가상함수 테이블(Virtual-Table)'을
만든다. 이는 실제로 호출되어야 할 함수의 위치정보를 담고 있는데 이를 기반으로 함수가 호출되며 오버라이딩 된
가상함수는 유도클래스의 가상 함수 테이블에 존재하지 않는다. 때문에 가장 마지막에 오버라이딩 한 유도 클래스의
멤버함수가 호출된다.



1
2
3
4
5
6
class A
{
   int i;
   char* c;
   void fun();
};
을 sizeof(A)를 하면 4(int i)+4(char*c, address)=8Bytes로 member function은 영향을 주지 않습니다. 
하지만,
?
1
2
3
4
5
6
class A
{
   int i;
   char* c;
   virtual void fun();
};
의 경우는 다릅니다. 
위의 8Bytes외에 실제 fun()이 binding을 위한 
실행함수 주소를 저장할 공간을 가리키는(VPTR) 4Bytes를 추가적으로 가지므로, 
sizeof(A)는 총 12Bytes가 됩니다.
이때
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class A
{
public:
   virtual void fun() { printf("A::fun() "); }
};
  
class B: public A
{
public:
   void fun() { printf("B::fun() "); }
};
  
void main()
{
   A* a = new B();
   memset(a, 0, sizeof(B));
   a->fun();
}
와 같이 memset을 이용하여 초기화를 하면, virtual function이 NULL영역으로 binding이 되어
a→fun();에서 run-time에 알 수 없는 에러가 발생한다는 것을 반드시 기억해야 합니다.

memset은 매우 편리하고, 강력하면서도, 조심해서 사용해야 한다는 것을 명심하세요.

댓글

이 블로그의 인기 게시물

(네트워크)폴링방식 vs 롱 폴링방식

(ElasticSearch) 결과에서 순서 정렬

(18장) WebSocekt과 STOMP를 사용하여 메시징하기