'가상함수'에 해당되는 글 2건

  1. 2012.08.22 가상함수의 동작원리와 가상함수 테이블
  2. 2012.08.19 가상 함수 (Virtual Function)

가상함수의 동작원리




A 클래스를보면 virtual 가상함수가 존재한다. 이렇듯 한 개 이상의 가상함수를 포함하는 클래스에 대해서는 컴파일러가 "가상함수 테이블" 이란 것을 만든다. 

이를 간단히 "V-Table(virtual table)" 이라고도 하는데, 이는 실제 호출되어야 할 함수의 위치정보를 담고 있는 테이블 이다.


가상테이블을 확인하면 A 클래스의 Func1에 대한 정보가 존재하지 않는다. 


- 이렇듯, 오버라이딩 된 가상함수의 주소정보는 유도 클래스의 가상함수 테이블에 포함되지 않는다. 때문에 오버라이딩 된 가상함수를 호출하면, 무조건 가장 마지막에 오버라이딩을 한 유도 클래스의 멤버함수가 호출되는 것이다.




가상함수 테이블이 참조되는 방식


- main 함수가 호출되기 이전에 가상함수 테이블이 메모리 공간에 할당된다. 참고도 가상함수 테이블은 객체의 생성과 상관없이 메모리 공간에 할당된다. 

이는 가상함수 테이블이 멤버함수의 호출에 사용되는 일종의 데이터이기 때문이다. 


※ 가삼함수를 하나이상 멤버로 지니는 클래스의 객체에는 가상함수 테이블의 주소 값이 저장된다. 물론 이 주소 값은 우리가 직접 참조할 수 있는 주소 값이 아니다. 내부적으로 필요에 의해서 참조되는 주소 값일 뿐이다.



>>>>>> 결론


# B 클래스의 가상함수를 살펴보면, 오버라이딩 된 A 클래스의 Func1 함수에 대한 정보가 없음을 알 수 있다. 

그래서 B클래스의 Func1 함수가 대신 호출되는데, 이것이 바로 가상함수의 호출원리이다.



※ 가상함수 테이블에 의한 속도의 저하

- 위에서 설명했듯이 클래스에 가상함수가 포함되면, 가상함수 테이블이 생성되고, 또 이 테이블을 참조하여 호출될 함수가 결정되기 때문에 실행속도가 감소하기 마련이다. 하지만 그 속도의 차이가 극히 미미하고 또 이러한 단점에도 불구하고 가상함수는 많은 장점을 제공하기 때문에 유용하게 활용되는 것이다.

Posted by scii
:



※ C++ 컴파일러는 포인터를 이용한 연산의 가능성 여부를 판단할 때, 포인터의 자료형을 기준으로 판단하지, 실제 가리키는 객체의 자료형을 기준으로 판단하지 않는다.


위의 예제에서 func함수는 모두 오버라이딩 관계를 형성하고 있다. 


fptr->Func();         => fptr이 First형 포인터이니, 이 포인터가 가리키는 객체를 대상으로 First 클래스에 정의된 Func()함수는 무조건 호출한다. 


sptr->Func();        => sptr이 Second형 포이터이니, 이 포인터가 가리키는 객체에는 First의 Func함수와 Second의 Func함수가 오버라이딩 관계로 존재한다. 그래서 오버라이딩을 한 Second함수의 Func함수를 호출한다. 



## 가상함수


가상함수를 쓰는 이유? 

"함수를 오버라이딩을 했다는 것은, 해당 객체에서 호출되어야 하는 함수를 바꾼다는 의미인데, 포인터 변수의 자료형에 다라서 호출되는 함수의 종류가 달라지는 것은 문제가 있어 보인다."


그래서 C++은 이러한 상황이 발생하지 않도록 "가상함수"라는 것을 제공한다. 그런데 이 가상함수라는 것은 C++의 개념이 아닌 객체지향의 개념이다. 따라서 C++뿐만이 아니라 JAVA, C#과 같은 객체제향 언어에서도 이와 동일한 개념의 문법이 제공되고 있다. 


가상함수의 선언은 virtual 키워드의 선언을 통해서 이뤄진다. 그리고 이렇게 가상함수가 선언되고 나면, 이 함수를 오버라이딩 하는 함수도 가상함수가 된다. 




함수가 가상함수로 선언되면, 해당 함수호출 시 포인터의 자료형을 기반으로 호출대상을 결정하지 않고, 포인터 변수가 실제로 가리키는 객체를 참조하여 호출의 대상을 결정한다. 

    

Posted by scii
: