<div>우선 제가 멤버함수와 가상함수에 대해서 이해한 부분은 다음과 같습니다.</div> <div> </div> <div> </div> <div>1. 일단 기본적으로 일반 멤버함수에 대해서</div> <div> </div> <div>함수 Func1을 일반 멤버함수로 갖는 클래스 Base와,</div> <div>Base를 상속하며, Func1을 오버라이딩한 클래스 Derived이 있다고 할 때,</div> <div> </div> <div>Base::Func1 과 Derived::Func1 이 코드세그먼트에 먼저 올라간뒤,</div> <div> </div> <div>Base와 Derived 객체들이 Func1에 접근할 때, 함수포인터 형태로 해당 함수에 접근한다고 알고 있습니다.</div> <div> </div> <div>이때, Base의 포인터에 Derived 객체를 넣은 뒤 Func1을 호출하면 Derived::Func1이 아닌 Base::Func1이 호출된다고도 알고있습니다.</div> <div> </div> <div>이를 봤을 때, 제 생각에는,</div> <div>컴파일러는 각 객체 내부에 맴버변수로 Base::Func1 또는 Derived::Func1 의 함수포인터를 넣어둔 뒤 호출하는 방식으로 멤버함수 호출을 구현하는 것이 아니라, 컴파일 타임에서 포인터의 형태에 맞는 Func1 주소를 인스트럭션으로 삽입하는 형태로 구현하는 것이라고 생각했습니다.</div> <div> </div> <div>그래야만, 실제 동작이 그러하듯, 객체의 실제 클래스가 아니라 포인터의 자료형에 따른 함수 호출이 가능할테니까요.</div> <div> </div> <div> </div> <div>2. 가상함수에 대해서</div> <div> </div> <div>가상함수 테이블을 컴파일러가 생성하고, 이를 데이터세그먼트에 올린 다음, 각 가상함수 테이블을 객체의 멤버변수 형태로 보관하고 있다가</div> <div>객체가 가상함수에 접근할 때, 가상함수 테이블로 점프한 뒤 테이블을 참조하여 적절한 함수를 호출한다고 알고있습니다.</div> <div> </div> <div> </div> <div>각 각의 방식에 대해서 떼어놓고 본다면 아무런 의문도 생기지 않습니다. 그런데 이 둘을 합치려니까 의문점이 생깁니다.</div> <div> </div> <div>첫 째로, 일반 멤버함수의 형태와 가상함수의 형태로 나눌 필요가 있느냐 하는것입니다. 만일 제 생각대로 컴파일러가 1과 2의 구현을 다른 식으로 한다면, 컴파일 시간만 더 잡아먹는 것 아닌가요? 차라리 일반 멤버함수, 가상함수 구분없이 각 클래스에 대한 함수 테이블을 만든 뒤에 각 객체가 테이블 주소를 메타데이터로 갖고있으면,</div> <div> </div> <div>"객체->함수테이블->함수" 형태로 구현을 일원화 할 수 있는것 아닌가요?</div> <div> </div> <div>구현이 이원화 되어있으면 컴파일러는 클래스에 가상함수가 있는지 없는지를 먼저 판단하고 호출방식도 달리해야하는데 이는 상당히 비효율적이지 않나요?</div> <div> </div> <div>둘 째로, 만약 제 생각이 틀리고, 1과 2의 구현이 같은 방식이라면, 어째서 Base 포인터에 Derived 객체를 넣은 뒤 Func1을 호출할 때 컴파일러는 실제 객체의 타입이 아니라, 포인터의 타입을 기준으로 함수호출을 판단하는 것인가요?</div>
댓글 분란 또는 분쟁 때문에 전체 댓글이 블라인드 처리되었습니다.