https://velog.io/@dev_sensational/C-VTable%EA%B3%BC-%EB%8B%A4%ED%98%95%EC%84%B1
저번 포스트에서 VTable과 다형성에 관련된 글을 다뤘습니다. 그런데 순수 가상 함수에 대한 잘못된 정보와 실험 때문에 오류가 있어 정정하고자 포스트를 작성하게 되었습니다.
순수 가상 함수는 일반 가상 함수와 마찬가지로 Vtable에 함수 포인터 슬롯으로 들어갑니다. 그런데 순수 가상 함수는 실체화될 수 없기 때문에 실제 객체가 존재하지 않고, 객체가 존재하지 않으니 그 객체를 가리킬 포인터 또한 존재하지 않습니다.
때문에, 보통 컴파일러는 그 슬롯에 purecall handler를 넣습니다(e.g. MSVC의 __purecall, GCC의 __cxa_pure_virtual). 만약 파생 클래스가 오버라이드하면, vtable 엔트리는 그 오버라이드 함수의 포인터로 교체됩니다. 오버라이드가 없으면 여전히 __purecall 같은 런타임 에러 핸들러를 가리킵니다.
https://learn.microsoft.com/ko-kr/cpp/c-runtime-library/reference/purecall?view=msvc-170
실제 __purecall이 호출되는 부분과 고찰에 대한 이야기는 아래 블로그 글에서 확인해 볼 수 있습니다.
https://blog.naver.com/sorkelf/40171776440
그런데 VS에서 직접 __purecall을 실행해보려고 하면 런타임이 아닌 링크 단계에서 오류가 발생합니다.
struct Base
{
Base() { f(); }; // 생성자에서 순수가상 함수 호출
virtual void f() = 0;
};
struct Derived : Base
{
void f() override { std::cout << "Derived::f\n"; }
};
int main()
{
Derived d; // Derived 생성 시, Base 생성자 안에서 f() 호출 → __purecall 실행?
}

문서에 따르면 LNK2019는 다음과 같습니다.
함수에 대해 컴파일된 코드는 symbol을 참조하거나 호출하지만 링커는 라이브러리나 개체 파일에서 기호 정의를 찾을 수 없습니다.
즉, 컴파일은 정상적으로 완료했지만, 링커 단계에서 해당 심볼을 찾을 수가 없어서 오류가 발생하는 것인데, 이를 통해서 MSVC에서는 vtable 슬롯을 __purecall로 처리하고 끝이 아니라 Base::f의 심볼을 찾으려 한다고 예상할 수 있습니다.
C++가 점점 발전하면서 런타임에서 발생할 수 있는 에러를 사전에 발견하여 오류를 뱉도록 변화된 것이 아닌가 싶습니다. 개인적으로 아주 긍정적인 변화인 것 같네요.