(C++)가상함수(Virtual Function)
■ 가상 함수의 실체
객체 안에는 실제로 멤버함수가 존재하지 않는다. 실제로 C++의 객체와 멤버함수는 함수를 공유하는 구조를 가진다.
객체가 생성되면 멤버변수는 객체 내에 존재하지만, 멤버함수는 메모리의 한 공간에 별도로 위치하고선, 이 함수가
정의된 클래스의 모든 객체가 이를 공유하는 형태를 취한다.
virtual로 선언된 가상함수를 하나이상 포함하는 클래스에 대해서는 컴파일러가 '가상함수 테이블(Virtual-Table)'을
만든다. 이는 실제로 호출되어야 할 함수의 위치정보를 담고 있는데 이를 기반으로 함수가 호출되며 오버라이딩 된
가상함수는 유도클래스의 가상 함수 테이블에 존재하지 않는다. 때문에 가장 마지막에 오버라이딩 한 유도 클래스의
멤버함수가 호출된다.
객체 안에는 실제로 멤버함수가 존재하지 않는다. 실제로 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은 매우 편리하고, 강력하면서도, 조심해서 사용해야 한다는 것을 명심하세요.
댓글
댓글 쓰기