[말랑 퀴즈] 26/09/28 해답

게시:     수정

카테고리:

태그:

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

말랑말랑 퀴즈 — 해답지 ✅

날짜: 2026-09-28 문제 수: 6문제 총점: 40.8/60 (68점) 🟡 복습이 필요해요

📊 채점 결과

문항 유형 난이도 결과 점수
Q1 빈칸 🟢 쉬움 🔺 부분 정답 4.0 / 10
Q2 서술형 🔴 어려움 🔺 부분 정답 6.8 / 10
Q3 OX 🟡 보통 ⭕ 정답 10 / 10
Q4 객관식 🟡 보통 ⭕ 정답 10 / 10
Q5 객관식 🔴 어려움 ❌ 오답 0 / 10
Q6 빈칸 · 📌 오답노트 🟡 보통 ⭕ 정답 10 / 10
합계       40.8 / 60

총평

Q3, Q4, Q6은 만점입니다. 특히 Q6(오답노트)은 확장성/안정성 구분과 수평·수직 분산의 결과를 정확히 채우셨습니다(아래 Q6 피드백에 문제 설계상 아쉬운 점을 먼저 말씀드립니다).

Q1(MongoDB 절차)에서 순서가 밀렸습니다. ①과 ④는 맞았지만, ②·③·⑤가 어긋났는데 특히 ②·③은 한 칸씩 밀려 적힌 것처럼 보입니다.

Q2(핸들 반환)는 (1)~(3)은 준수한데 (4)에서 질문을 다르게 이해하신 것 같습니다. “핸들을 다른 함수로 전달하지 않는다”는 이 항목이 실제로 강조하는 내용이 아닙니다.

Q5(다중 상속)는 아쉽게 오답입니다. B(가상 상속의 비용)에 확신이 없으셨고, C에서 CPerson의 public/private 방향을 반대로 추측하신 것이 D를 고르게 된 원인으로 보입니다.


Q1. 🟢 쉬움 — 🔺 4.0/10

문제: 빈칸을 채우시오.

MongoDB 클라이언트를 쓸 때는 먼저 ① ___(을)를 매개변수로 연결 객체를 만들고, 그다음 ② ___(을)를 매개변수로 DB 인스턴스 액세스를 얻고, 그다음 ③ ___(을)를 매개변수로 컬렉션 액세스 객체를 얻는다. 도큐먼트를 삽입할 때는 ④ ___(이)라는 이진 형식의 객체를 사용하는데, 이는 JSON과 같은 역할을 하지만 ⑤ ___ 구조를 쓴다는 차이가 있다.

📝 내 답: 엔드포인트, 연결 객체, DB 인스턴스, BSON, 바이너리

정답:

① 엔드포인트 ② DB 인스턴스 이름 ③ 컬렉션 이름 ④ BSON(Binary JSON) ⑤ 트리(구조)

해설:

client = new client("mongodb::localhost:27017);  // ① 엔드포인트
db = client["mydb"];                              // ② DB 인스턴스 이름
coll = db["mycollection"];                         // ③ 컬렉션 이름

도큐먼트 삽입에는 BSON(Binary JSON) 객체를 쓰며, JSON과 역할은 같지만 트리 구조를 쓴다는 점이 특징이다.

🔍 피드백: ①, ④만 정답 처리해 4.0점입니다.

②·③이 한 칸씩 밀린 것 같습니다. ②에는 “DB 인스턴스 이름”(즉 "mydb" 같은 값)이 들어가야 하는데 “연결 객체”(1단계의 결과물 이름)를 적으셨고, ③에는 “컬렉션 이름”이 들어가야 하는데 “DB 인스턴스”(2단계의 결과물 이름)를 적으셨습니다. 각 단계에서 “무엇을 만드는가”가 아니라 “그걸 만들 때 넘기는 매개변수가 무엇인가”를 물었다는 점을 다시 봐 주세요.

⑤는 “이진(바이너리)”이 아니라 “트리” 구조입니다. 문장 앞부분에서 이미 “④(BSON)는 이진 형식”이라고 말했으므로, ⑤는 그것과 다른 축(자료구조 형태)의 차이 — JSON과 달리 트리 구조를 쓴다는 점을 묻는 자리였습니다.

출처: server/game_server/8/2026-03-14-game_server_8_9.md


Q2. 🔴 어려움 — 🔺 6.8/10

문제: 핸들 반환에 대해 답하시오.

struct RectData {
    Point ulhc; // 좌측 상단
    Point lrhc; // 우측 하단
};

class Rectangle {
public:
    Point& upperLeft() const { return pData->ulhc; }
    Point& lowerRight() const { return pData->lrhc; }
private:
    shared_ptr<RectData> pData;
};

(1) ulhc, lrhc는 private 멤버인데도, 캡슐화가 깨지는 이유는? (2) 반환 타입에 const를 붙이면 어떤 문제가 해결되며, 왜 그것만으로는 부족한가? (3) 아래 코드에서 무효참조 핸들 문제가 왜 생기는가?

const Rectangle boundingBox(const GUIObject& obj);
const Point* pUpperLeft = &(boundingBox(*pgo).upperLeft());

(4) 이 항목의 핵심 원칙은 “핸들 반환 함수는 절대 쓰지 말라”인가, 다른 뉘앙스인가?

📝 내 풀이:

(1) upperLeft와 lowerRight 함수에서 각 Point 객체의 참조를 반환하기 때문.

(2) const 객체, const 참조가 되어 변경이 불가능해진다. Rectangle이 소멸되면, 반환한 참조가 댕글링된다.

(3) boundingBox(*pgo)를 통해 Rectangle 객체가 생성되지만, 괄호 밖으로 나가는 순간 소멸한다.

(4) 받아온 핸들을 다른 함수로 전달하여 사용하지 않는다.

정답:

(1) 캡슐화 정도는 “그 데이터를 참조자로 반환하는 함수의 최대 접근도”로 정해진다

ulhc, lrhc는 private이지만 그 참조자를 반환하는 함수(upperLeft, lowerRight)가 public이라, 외부에서 참조자를 통해 내부를 마음대로 바꿀 수 있어 사실상 public이나 다름없다.

(2) const는 “상수성 위반”만 해결한다 — 캡슐화 파괴와 무효참조 핸들은 그대로다

const Point& upperLeft() const로 고치면 상수성 위반은 막히지만, 캡슐화는 여전히 깨져 있고 더 근본적으로 무효참조 핸들(dangling handle) 문제가 남는다 — 이게 핸들 반환의 가장 큰 문제다.

(3) boundingBox()가 값을 반환하므로, 임시 Rectangle이 문장이 끝나는 즉시 소멸된다

임시 Rectangle과 그 안의 Point들이 문장이 끝나면 함께 소멸되어, pUpperLeft는 이미 사라진 객체를 가리키는 무효참조 핸들이 된다.

(4) “절대 쓰지 말라”가 아니라 “되도록 피하라”는 뉘앙스다

핵심 원칙은 “위험하니 되도록 피하라”이지 전면 금지는 아니다 — 어쩔 수 없이 필요한 경우도 있다고 원문은 명시한다.

🔍 피드백: 논점별로 (1) 2.0 / (2) 2.1 / (3) 2.3 / (4) 0.4를 받아 6.8점입니다.

(1)은 핵심 메커니즘(참조자 반환)은 정확히 짚으셨지만, “왜 그게 캡슐화를 깨는가”까지는 설명이 없습니다 — 정답의 핵심은 “캡슐화 정도는 데이터 자체가 아니라, 그 데이터를 노출하는 함수 중 가장 접근하기 쉬운 함수로 정해진다”는 원리입니다.

(2)는 “const로 뭐가 해결되는지”와 “댕글링 문제가 남는다”는 정확히 맞혔습니다. 다만 “왜 const만으로 부족한가”에 대한 또 다른 이유 — 캡슐화 자체는 여전히 깨져 있다는 점(비상수 객체에 대해서는 내부가 그대로 노출됨) — 이 빠졌습니다.

(3)은 거의 만점입니다. “괄호 밖으로 나가는 순간 소멸”이라는 표현이 “문장이 끝나는 즉시 소멸”과 완전히 같은 뜻이라 정확합니다.

(4)는 질문의 의도와 다른 답을 하신 것 같습니다. 이 질문은 “이 항목의 원칙이 얼마나 강한 금지인가”(절대 금지 vs 되도록 피하기)를 묻는 것이었는데, “핸들을 다른 함수에 전달하지 않는다”는 원문에 나오지 않는 별개의 완화 기법을 적으셨습니다. 원문은 명확히 “피하자(avoid)”라고 표현하며, “어쩌다 보면 필요한 경우가 있다”고 여지를 남깁니다 — “절대 쓰지 말라”는 더 강한 주장과는 결이 다릅니다.

출처: game_dev/cpp/chapter5/2025-07-10-cpp_5_28.md


Q3. 🟡 보통 — ⭕ 10/10

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

프라우드넷에서 NetServer 클래스는 게임 클라이언트의 네트워크 모듈로, 서버에 연결을 맺고 메시지를 주고받으며 다른 클라이언트와 P2P 통신도 할 수 있다. 반면 NetClient 클래스는 게임 서버의 메인 모듈로, 클라이언트 연결을 받고 각 클라이언트의 네트워크 상황을 열람할 수 있다.

📝 내 답: X. NetServer과 NetClient 단어를 서로 바꿔야 맞다.

정답: X

해설:

두 클래스의 역할이 정반대로 뒤바뀌어 있다. NetServer는 게임 서버의 메인 모듈(클라이언트 연결 수신, 메시지 송수신, 네트워크 상황 열람), NetClient는 게임 클라이언트의 네트워크 모듈(서버 연결, 메시지 송수신, P2P 통신)이다.

🔍 피드백: 만점입니다. “두 단어를 서로 바꿔야 한다”는 정답 해설의 핵심을 정확히, 가장 간결하게 짚으셨습니다.

출처: server/game_server/6/2026-02-18-game_server_6_2.md


Q4. 🟡 보통 — ⭕ 10/10

문제: 프라우드넷의 와이파이·셀룰러 연결 핸드오버(연결 유지) 기능에 대한 설명으로 가장 올바른 것은?

  • A. 연결 유지 기능(auto connection recovery)은 서버에서 기본적으로 켜져 있으며, 클라이언트에서는 별도 설정이 필요 없다.
  • B. 와이파이 지역을 벗어나 네트워크 통신이 일시적으로 멈추더라도, 연결이 회복되면 그동안 쌓인 메시지를 한 번에 받는다. 클라이언트는 OnServerOffline/OnServerOnline 이벤트로, 서버는 OnClientOffline()/OnClientOnline() 함수로 이를 알 수 있고, P2P 연결에서는 상대(peer)에 대해서도 OnP2PMemberOffline/OnP2PMemberOnline이 추가로 호출된다.
  • C. 연결이 끊기고 회복되는 동안 발생한 메시지는 유실되며, 애플리케이션이 별도로 재전송을 요청해야 한다.
  • D. P2P 연결에서는 별도의 오프라인/온라인 이벤트가 없으며, 서버-클라이언트 연결의 이벤트만으로 피어 상태를 알 수 있다.

📝 내 답: B — A: 클라이언트에서 별도의 설정이 필요했던 것 같다. / C: 유실되지 않으며, 보관되었다가 한번에 받는다. / D: B에 설명한 것처럼 OnP2PMember~~ 과 관련된 함수가 있다.

정답: B

해설:

연결 유지 기능은 클라이언트에서 활성화해야 하며, 통신이 끊겨도 회복되면 쌓인 메시지를 한 번에 받는다.

주체 오프라인 온라인
클라이언트 OnServerOffline OnServerOnline
서버 OnClientOffline() OnClientOnline()
P2P(피어) OnP2PMemberOffline OnP2PMemberOnline
  • A — 반대다. 클라이언트에서 활성화해야 한다.
  • C — 메시지는 유실되지 않고 회복 시 한 번에 받는다.
  • D — P2P에서는 피어에 대한 별도 이벤트가 추가로 있다.

🔍 피드백: 만점입니다. A·C·D에 대한 반박 모두 정확합니다.

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


Q5. 🔴 어려움 — ❌ 0/10

문제: 다중 상속에 대한 설명으로 가장 올바른 것은?

  • A. 두 기반 클래스에 이름이 같은 함수가 있으면, 한쪽이 public이고 다른 쪽이 private이라는 접근 지정자 차이만으로 컴파일러가 자동으로 모호성을 해결해 준다.
  • B. 죽음의 마름모꼴(Deadly Diamond) 문제는 가상 상속(virtual public)으로 기반 클래스 복사본을 하나로 줄여 해결할 수 있지만, 그 대가로 객체 크기 증가·접근 속도 저하·초기화 복잡도 증가라는 비용이 따른다. 그래서 꼭 필요할 때만 가상 상속을 쓰고, 쓰더라도 가상 기본 클래스에는 데이터를 두지 않는 것이 좋다.
  • C. CPerson이 IPerson은 private으로, PersonInfo는 public으로 상속한 이유는, 인터페이스 구현에는 재정의가 필요 없어 private을, 구현 도우미에는 다형적 확장이 필요해 public을 쓰기 때문이다.
  • D. 다중 상속은 항상 피해야 하며, 이펙티브 C++은 단일 상속만으로 설계할 것을 권장한다.

📝 내 답: D — A: 이름이 같은 함수는 접근 지정자가 다르다 해도 영향을 받는다. / B: 죽음의 마름모꼴이라는 것은 기억나지만, 이걸 어떻게 해결했는지 정확히 기억나지 않는다. / C: private 상속을 하였더라도 재정의가 가능하다. 문제에 코드가 없어서 못보지만 아마 인터페이스 내부 함수/변수를 private로 두기 위함일 것이다. 구현 도우미는 다형적 확장(is-a 관계) public을 썼을 것이다.

정답: B

해설:

문제 1(이름 모호성): public/private 차이는 모호성 해결에 전혀 관여하지 않는다 — 컴파일러는 접근 가능성을 점검하기 전에 이미 모호성 에러를 낸다.

문제 2(죽음의 MI 마름모꼴): 가상 상속으로 기반 클래스 복사본을 하나로 줄일 수 있지만, 객체 크기 증가·접근 속도 저하·초기화 복잡도 증가라는 비용이 든다. 그래서 “필요 없으면 비가상 상속, 써야 한다면 가상 기본 클래스에 데이터 두지 않기”가 원칙이다.

다중 상속의 올바른 사용 예: CPerson : public IPerson, private PersonInfo — 인터페이스(IPerson)는 public(구현해서 외부에 노출해야 하므로), 구현 도우미(PersonInfo)는 private(is-implemented-in-terms-of 관계이며, 일부 함수를 재정의해야 하므로) 상속한다.

  • A — 반대다. 접근 가능성 점검 이전에 이미 모호성 에러가 난다.
  • C — public/private이 뒤바뀌었다. IPerson이 public, PersonInfo가 private이다.
  • D — 항목 40의 결론은 “심사숙고해서 사용하자”이지 전면 금지가 아니다.

🔍 피드백: 정답 B를 확신하지 못하고 D를 고르셨습니다.

A에 대한 반박은 정확했습니다 — “접근 지정자가 달라도 영향을 받는다”(즉 모호성이 그대로 생긴다)는 정답과 일치합니다.

B에 대해서는 “기억이 안 난다”고 솔직하게 적으셨는데, 이게 정답이었습니다. 가상 상속의 해결책과 비용(크기·속도·초기화 복잡도) 세 가지를 다시 보시면 좋겠습니다.

C에 대한 추측이 실제로는 정답과 정반대 방향입니다. “인터페이스는 private, 구현 도우미는 public”이라고 추측하셨는데, 실제로는 인터페이스(IPerson)가 public, 구현 도우미(PersonInfo)가 private입니다 — 인터페이스는 외부에 공개해서 구현해야 하니 public, 구현 도우미는 내부 구현 세부사항(일부 함수 재정의)을 감춰야 하니 private입니다. C를 이렇게 잘못 판단하신 것이, 결과적으로 D를 고르시게 된 것과 무관하지 않아 보입니다 — 이 방향을 확실히 정리해 두시면 다음엔 헷갈리지 않으실 것 같습니다.

출처: game_dev/cpp/chapter6/2025-10-28-cpp_6_40.md


Q6. 🟡 보통 · 📌 오답노트 — ⭕ 10/10

문제: 빈칸을 채우시오.

분산 처리는 ① ___뿐 아니라 ② ___에도 도움이 된다는 점에서, 단순히 서버 한 대의 성능을 올리는 ③ ___(과)는 다른 가치를 가진다. 수평 분산에서 서버 한 대가 멈추면 그 서버에 있던 플레이어는 접속이 끊기지만, ④ ___할 수 있어 완전히 게임을 못 하게 되는 것은 아니다. 수직 분산에서 서버 한 대가 멈추면, 다른 서버들은 ⑤ ___하지만 멈춘 서버가 맡았던 기능은 ⑥ ___.

📝 내 답: 확장성, 안정성, 수직 분산, 다른 서버에서 플레이, 정상 작동, 멈춘다.

(추가로 “답안이 여러가지 나올 수 있어, 모호한 문제는 내지 못하게 해야겠다”는 메모를 남기셨습니다 — 아래 피드백에서 이 부분부터 말씀드립니다.)

정답:

① 확장성 ② 안정성 ③ 서버 업그레이드(scale-up) ④ 다른 서버에 접속 ⑤ 정상 작동 ⑥ 대체할 수 없다 (그 기능만 못 쓴다)

해설:

분산 처리는 확장성뿐 아니라 안정성에도 효과를 준다. 단순히 서버 한 대의 사양을 올리는 서버 업그레이드(scale-up)는 그 한 대가 죽으면 전체가 멈추지만, 분산 처리는 다르다.

  • 수평 분산: 중지된 서버에 있던 플레이어들만 접속이 끊기고, 다른 서버에 접속하면 계속할 수 있다.
  • 수직 분산: 중지된 서버가 맡던 그 기능만 못 쓰게 되고, 나머지 기능(다른 서버들)은 정상 작동한다.

🔍 피드백: 만점으로 정정했습니다. 다만 남기신 메모가 정당합니다 — ③번 빈칸(“서버 업그레이드/scale-up”)은 사실 이번에 읽은 원문(game_server_9_11.md)에는 등장하지 않는 용어입니다. 이 오답노트 항목이 예전(2026-09-10)에 처음 등록될 때 “scale-up과 구분해야 한다”는 메모가 남아 있어 이번 문제에 그대로 반영했는데, 정작 이 포스트 자체에는 그 대조 대상이 나오지 않아 확인할 방법이 없는 채로 출제된 것이 문제였습니다. “수직 분산”이라고 답하신 것은 원문에 실제로 있는 단어를 쓰신 것이라 억지 오답으로 볼 수 없어, 이번엔 감점하지 않았습니다.

나머지는 모두 정확합니다 — ①②는 정확히 일치하고, ④”다른 서버에서 플레이”는 “다른 서버에 접속”과 같은 뜻, ⑤도 정확, ⑥”멈춘다”도 “대체할 수 없다”(그 기능을 못 쓰게 된다)와 사실상 같은 내용이라 정답 처리했습니다.

앞으로는 이 항목을 오답노트로 다시 낼 때 scale-up 관련 빈칸은 빼거나, 출처 원문에 있는 내용만으로 빈칸을 구성하도록 유의하겠습니다.

출처: server/game_server/9/2026-03-22-game_server_9_11.md 오답노트: wn-5e7f462f · 2026-09-10 최초 오답 · 이번이 2번째 복습


📌 복습 포인트

  • Q1 MongoDB 3단계 절차 — 엔드포인트 → DB 인스턴스 이름 → 컬렉션 이름 순서로 매개변수가 바뀌며, BSON은 JSON과 달리 트리 구조 → server/game_server/8/2026-03-14-game_server_8_9.md
  • Q2 핸들 반환 원칙의 강도 — “절대 금지”가 아니라 “되도록 피하라(avoid)”는 더 약한 권고라는 점 → game_dev/cpp/chapter5/2025-07-10-cpp_5_28.md
  • Q5 CPerson의 public/private 상속 방향 — 인터페이스는 public(외부에 구현을 노출), 구현 도우미는 private(내부 세부사항, 재정의 필요) → game_dev/cpp/chapter6/2025-10-28-cpp_6_40.md

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

댓글남기기