C++] 가상 함수를 생성자에 사용하면??
최근 기업 시험을 보는데 이런 문제가 나왔습니다.
"가상함수를 생성자에 사용한다면 어떻게 되는가?"
이 문제를 봣을 때 "이건 뭐지??" 라는 생각이 먼저 들었습니다.
왜냐하면 생성자에서 가상함수를 호출할 생각 자체를 제 평생 한번도 해본적이 없기 때문입니다.
왜냐??
사용할 이유가 없으니깐요.... 가상 함수니깐요....
가상 함수의 의미는? overriding 이죠. 다형성이죠.
또한 순수 가상 함수는 재 정의를 해줘야하는 함수입니다.
재 정의를 해야할 함수를 생성자를 통해 호출을한다??
아마 사용자의 실수로 호출을 하지 않을까... 싶네요....
코드가 길어지면 어느 클래스에 어떤 맴버함수가 있는지 잘 기억이 안나니깐 말이죠...
그래서 저는.... 찾아보고....경험해보고.... 그래서 이 글을 쓰게 됩니다.....
그럼 코드를 한번 보시죠!!
예제 1
자!! 결과가 이상합니다. 생각했던 시나리오를 읊어보겠습니다.
1. B b; 객체를 만든다.
2. 상속관계 이므로 부모 생성자가 먼저 호출된다.
3. 부모 생성자 안에 fn();
함수를 호출해주네??
4. fn()
함수는 가상함수네??
5. 근데 지금 호출한 객체는 class B 의 객체네??
6. 그럼 v-table에 의거해 B의 함수가 호출 되겠지? ㅎㅎ
이런 시나리오 입니다.
하지만 정~말 잘못된 생각이구요.
그럼 코드의 흐름대로 읊어보겠습니다.
1. B b; 객체를 만든다.
2. 상속관계 이므로 부모 생성자가 먼저 호출된다.
3. 부모 생성자 안에 fn();
함수를 호출해주네??
4. 응~ 부모 함수 호출해!!
5. ???
왜 v-table에 의거하여 override된 함수가 호출이 안될까요??
A생성자가 호출되는 지점에서 디스어셈블리를 한 모습입니다.
여길 보시면 A의 v-table이 호출되는걸 알 수 있습니다.
B의 v-table이 아니란 말이죠.
이 이유는 초기화에 있습니다.
생성자의 특징은 딱 1번 호출만 된다는 점입니다.
그리고 이 호출 과정에선 자기 자신의 객체만 볼 수 있다는 점입니다.
다시말해서 virtual로 함수가 override됬어도, 해당 생성자 입장에선 자기자신 클래스만 본다는 점입니다.
왜그럴까요??
메모리에 적제될 때 부모 맴버변수들 부터 적재됩니다. 다시말해서 A 클래스의 생성자가 호출되는 시점에선
메모리상엔 자식 클래스에 대한 데이터 값은 없는 것이죠. 또한 앞서 말했듯 생성자 입장에선 자기 자신밖에 볼 수 없습니다.
초기화 과정이니깐요.
다른 예제를 봐볼까요??
예제 2
포인터로 바꾸고, upcast를 해도 똑같죠??
new B()
가 먼저 실행되면서 예제 1번과 똑같이 흘러가기 때문입니다.
더 최악인 예제를 봅시다.
예제3
순수 가상 함수를 부모 클래스에서 호출하게된다면???
이건 실행조차 안됩니다.
왜 실행조차 안될까요??
바로 정의도 되지 않은 fn();
함수를 호출하기 때문입니다.
왜냐?? 예제 1번과 마찬가지로 A생성자가 호출되는 시점에선 B 클래스를 볼 수 없기 때문에,
정의되지 않은 순수 가상 함수를 호출하게 되는것이죠.
그럼 링크에서 error가 날 수밖에 없는 것이죠.....
정의도 안됬는데..... 저기에 어떤 값을 넣을 수도 없는데.... 컴파일된 오브젝트 파일을 어떻게 링크 하냐!!....
쩝... 이상입니다.