49. 공변 반환 타입과 반환 포인터 조정(covariant return / pointer adjustment)
난이도 중 해설 보기 →
결함을 모두 찾고 원인·수정안·더 나은 설계를 제시하라. 마커
(A)(B) 는 주목 위치 힌트다.
결함 코드 · C++
// 주제: 가상 함수의 공변 반환 타입(covariant return type)과, 반환 포인터의
// 런타임 조정(pointer adjustment) — 반환 타입이 다중 상속으로 base 서브오브젝트가
// 오프셋 0이 아닐 때 vtable 썽크가 반환 포인터를 조정한다.
//
// 과제:
// 1) 다음 각 줄의 표준출력을 정확히 예측하라.
// 2) Factory* 를 통해 make() 를 부르면 반환형이 RetBase* 인데, 실제 구현은
// RetDerived* 를 돌려준다. 이때 반환된 포인터 값이 어떻게 조정되는지 설명하라.
// 3) L2 의 오프셋(두 포인터 차)이 왜 그 값이 되는지 RetDerived 레이아웃으로 설명하라.
// (내부 동작 설명은 answer.md 에만. 여기서는 예측만.)
//
// 컴파일: g++ -std=c++17 -O2 problem.cpp && ./a.out
#include <iostream>
#include <cstdint>
struct RetBase {
int x = 10;
virtual ~RetBase() {}
};
struct Pad {
long long p = 0;
virtual ~Pad() {} // Pad 를 다형적으로 만들어 primary base(오프셋 0)로 만든다
virtual void tick() {}
};
struct RetDerived : Pad, RetBase { // RetBase 는 오프셋 0이 아님
int y = 20;
};
struct Factory {
virtual ~Factory() {}
virtual RetBase* make() = 0;
};
struct ConcreteFactory : Factory {
RetDerived storage;
RetDerived* make() override { return &storage; } // 공변 반환: RetDerived* -> RetBase*
};
int main() {
ConcreteFactory cf;
Factory* f = &cf;
RetBase* rb = f->make(); // 정적 반환형 RetBase* (썽크가 조정)
RetDerived* rd = cf.make(); // 정적 반환형 RetDerived*
std::cout << std::boolalpha;
std::cout << rb->x << "\n"; // L1
std::cout << (reinterpret_cast<char*>(rb) - reinterpret_cast<char*>(rd)) << "\n"; // L2
std::cout << (static_cast<RetDerived*>(rb) == rd) << "\n"; // L3
std::cout << rd->y << "\n"; // L4
return 0;
} 내 리뷰 · C++
내 답안 · 자동 저장
작성 후 위 해설 보기에서 모범 해설과 대조하세요.