[말랑 퀴즈] 26/04/02 해답

게시:     수정

카테고리:

태그:

제 말랑말랑 퀴즈 생성기는 이곳에서 확인하실 수 있습니다.

말랑말랑 퀴즈 — 해답지 ✅

날짜: 2026-04-02 문제 수: 5문제


Q1. 🔴 어려움

문제: C++에서 iterator_traits와 함수 오버로딩을 결합해 advance 함수를 구현하려 한다.

아래는 잘못된 구현 예시이다.

template<typename IterT, typename DistT>
void advance(IterT& iter, DistT d) {
    if (typeid(typename iterator_traits<IterT>::iterator_category)
        == typeid(random_access_iterator_tag)) {
        iter += d;
    } else {
        if (d >= 0) { while (d--) ++iter; }
        else        { while (d++) --iter; }
    }
}
  1. typeid 기반 구현이 잘못된 이유를 설명하시오. (컴파일 시점과 런타임 시점의 차이에 주목하라)
  2. 올바른 해결책인 “작업자(worker) 함수 오버로딩 + 주작업자(master) 함수” 패턴이 어떻게 이 문제를 해결하는지 설명하시오.
  3. 반복자 태그 구조체들이 is-a 상속 관계로 설계된 이유는 무엇인가?

정답:

1. typeid 방식의 문제

iterator_traits<IterT>::iterator_category컴파일 도중에 결정되는 타입 정보이다. 그러나 if문은 런타임에 평가된다. 즉, 타입에 대한 분기를 런타임에 수행하려 하기 때문에 잘못된 접근이다. 컴파일러 입장에서는 모든 if의 양쪽 분기를 컴파일해야 하는데, 예를 들어 입력 반복자로 advance를 호출하면 iter += d 코드가 컴파일되지 않아 에러가 발생한다.

2. 작업자 + 주작업자 패턴

반복자 종류마다 별도의 doAdvance 오버로드를 만들고, 세 번째 매개변수로 반복자 태그 타입을 받게 한다.

// 임의 접근 반복자용
template<typename IterT, typename DistT>
void doAdvance(IterT& iter, DistT d, random_access_iterator_tag) {
    iter += d;
}

// 양방향 반복자용
template<typename IterT, typename DistT>
void doAdvance(IterT& iter, DistT d, bidirectional_iterator_tag) {
    if (d >= 0) { while (d--) ++iter; }
    else        { while (d++) --iter; }
}

// 입력 반복자용 (순방향 반복자도 포함)
template<typename IterT, typename DistT>
void doAdvance(IterT& iter, DistT d, input_iterator_tag) {
    if (d < 0) throw out_of_range("Negative distance");
    while (d--) ++iter;
}

// 주작업자: iterator_category를 구해 doAdvance에 전달
template<typename IterT, typename DistT>
void advance(IterT& iter, DistT d) {
    doAdvance(iter, d,
        typename iterator_traits<IterT>::iterator_category());
}

컴파일러는 iterator_category 타입을 보고 컴파일 타임에 적절한 doAdvance 오버로드를 선택한다. 이로써 런타임 분기 없이 타입별로 다른 구현을 적용할 수 있다.

3. 태그 구조체가 is-a 상속 관계인 이유

forward_iterator_taginput_iterator_tag를 상속하고, bidirectional_iterator_tagforward_iterator_tag를 상속한다. 이 덕분에 input_iterator_tag를 받는 doAdvance에 순방향 반복자도 자동으로 매핑된다. 별도의 순방향 반복자용 오버로드를 만들지 않아도, 상속 관계를 통해 컴파일러가 가장 가까운 베이스 버전을 자동으로 선택한다.

출처: game_dev/cpp/chapter7/2025-11-02-cpp_7_47.md


Q2. 🟢 쉬움

문제: 렌더링 파이프라인에서 3D 도형이 픽셀로 변환되는 단계는 무엇인가?

  • A. Vertex Shader — 정점을 하나의 공통 좌표계(View Space)로 변환한다
  • B. Tessellation — 저해상도 메시를 고해상도 메시로 세분화한다
  • C. Rasterization — 3D 도형이 픽셀로 변환되며, 색 보간이 이루어진다
  • D. Fragment Shader — 픽셀에 라이팅·텍스처 등의 색을 입힌다

정답: C

해설:

Rasterization(래스터화) 단계에서 3D 도형이 픽셀로 변환된다. 정점 사이의 공간은 색 보간을 통해 픽셀에 반영되지만, 이 시점에서는 아직 최종 색깔이 결정되지 않는다. A(Vertex Shader)는 좌표 변환, B(Tessellation)는 메시 세분화, D(Fragment Shader)는 래스터화된 픽셀에 실제 색상(라이팅, 텍스처, 그림자 등)을 입히는 단계이다.

출처: graphics/2023-10-05-graphics-pipeline.md


Q3. 🟡 보통

문제: 다음 명제가 참(O)인지 거짓(X)인지 판단하라.

템플릿 파생 클래스에서 기본 클래스 템플릿의 멤버를 호출할 때, MsgSender<Company>::sendClear(info)처럼 명시적 한정(explicit qualification) 방식을 사용하면 가상 함수에 대해서도 안전하게 동적 바인딩이 이루어진다.

정답: X

해설:

명시적 한정 방식(MsgSender<Company>::sendClear(info))은 컴파일러가 기본 클래스 범위에서 해당 이름을 찾도록 강제하는 역할은 하지만, 가상 함수에 적용하면 가상 함수 바인딩(동적 디스패치)이 무력화된다. 즉, 런타임에 파생 클래스의 오버라이드된 함수가 아닌 기본 클래스의 함수가 직접 호출된다. 가상 함수를 포함한 경우의 안전한 방법은 this->sendClear(info) 또는 using MsgSender<Company>::sendClear; 선언을 사용하는 것이다.

출처: game_dev/cpp/chapter7/2025-10-30-cpp_7_43.md


Q4. 🟢 쉬움

문제: 빈칸을 채우시오.

JSON은 데이터 트리를 문자열로 표현한 포맷으로, 아래와 같은 구조를 가진다.

{
    "name" : "Alice",
    "score" : 100,
    "info" : { "level" : 5 },
    "items" : [10, 20, { "id" : 3 }]
}
  • JSON에서 {} 구문을 ___①이라 한다.
  • ①의 내부에는 __②(Key)와 __③(Value)의 쌍이 들어간다.
  • ②는 반드시 ___④로 둘러싸야 한다.
  • ③으로 올 수 있는 종류: 문자열, ___⑤, 객체, 배열

정답:

① 객체 ② 필드 이름 (Key) ③ 필드 값 (Value) ④ 큰따옴표(" ") ⑤ 숫자

해설:

JSON(JavaScript Object Notation)은 {} 중괄호로 객체를 표현하며, 객체 안에는 "키": 값 쌍이 들어간다. 키는 반드시 문자열이므로 큰따옴표로 감싸야 한다. 값으로는 문자열, 숫자, 또 다른 객체({}), 배열([])을 사용할 수 있으며, 배열 안에 다시 객체를 넣는 중첩 구조도 가능하다.

출처: server/game_server/8/2026-03-09-game_server_8_4.md


Q5. 🟡 보통

문제: 프라우드넷 기반 게임 서버에서 SendUserMessage()로 메시지를 전송할 때, 전송 방식에 대한 설명으로 옳지 않은 것은?

  • A. ReliableSend는 TCP 기반으로 전송을 보장하므로 아이템 획득·채팅 같은 중요한 데이터에 적합하다
  • B. UnreliableSend는 UDP 기반으로 전송 속도가 빠르므로 캐릭터 위치·상태 같은 실시간 데이터에 적합하다
  • C. RmiContext 구조체에는 reliable/unreliable 외에도 암호화, 압축, 오래된 메시지 건너뛰기 등의 옵션이 포함된다
  • D. SendUserMessage()는 단일 클라이언트에게만 전송할 수 있으며, 다수 클라이언트에게 동시 전송하려면 별도의 브로드캐스트 함수를 사용해야 한다

정답: D

해설:

SendUserMessage()는 단일 클라이언트뿐 아니라 HostID 배열을 인자로 넘겨 다수의 클라이언트에게 동시에 전송할 수 있다.

HostID sendTo[10];
s->SendUserMessage(sendTo, 10, RmiContext::UnreliableSend, data, 30);

별도의 브로드캐스트 함수가 필요하지 않다. A, B, C는 모두 올바른 설명이다. RmiContext는 전송 신뢰성 외에도 암호화, 압축, 오래된 메시지 건너뛰기 같은 옵션을 포함하는 구조체이다.

출처: server/game_server/6/2026-02-23-game_server_6_4.md


MallangQuiz 카테고리 내 다른 글 보러가기

댓글남기기