[말랑 퀴즈] 26/09/16 문제
카테고리: MallangQuiz
태그: Quiz
제 말랑말랑 퀴즈 생성기는 이곳에서 확인하실 수 있습니다.
말랑말랑 퀴즈 📝
날짜: 2026-09-16 문제 수: 6문제
Q1. 🟡 보통
Customer 클래스에 복사 생성자와 복사 대입 연산자를 직접 정의해 두었다. 이 상태로 잘 동작하고 있었다.
class Customer {
public:
Customer(const Customer& rhs);
Customer& operator=(const Customer& rhs);
private:
std::string name;
};
Customer::Customer(const Customer& rhs)
: name(rhs.name)
{
logCall("Customer 복사 생성자");
}
Customer& Customer::operator=(const Customer& rhs)
{
logCall("Customer 복사 대입 연산자");
name = rhs.name;
return *this;
}
그러다 기획이 바뀌어 데이터 멤버를 하나 추가했다. 복사 함수는 손대지 않았다.
class Customer {
...
private:
std::string name;
Date lastTransaction; // ← 새로 추가
};
이 상황에 대한 설명으로 가장 올바른 것은?
- A. 컴파일러가 새 멤버
lastTransaction의 복사를 기존 복사 함수에 자동으로 끼워 넣어 주므로 문제없다. 복사 함수를 직접 정의했더라도 멤버별 복사는 컴파일러가 보장한다. - B. 복사 함수가 새 멤버를 다루지 않으므로 컴파일 에러가 나서 곧바로 발견된다. 그래서 실무에서는 이 실수가 거의 일어나지 않는다.
- C. 컴파일은 문제없이 되지만 복사가 부분적으로만 이루어져, 복사된 객체의
lastTransaction은 원본 값이 아니라 초기값을 그대로 갖는다. 그래서 데이터 멤버를 추가하면 복사 함수도 함께 수정해야 하며, 이것이 “객체의 모든 부분을 빠짐없이 복사하라”는 규칙의 첫 번째 의미다. 상속 관계에서 기본 클래스 부분을 명시적으로 복사해야 하는 것은 같은 규칙의 두 번째 의미다. - D. 복사 함수를 직접 정의했더라도 컴파일러가 만든 기본 복사 함수가 뒤이어 함께 실행되어 나머지 멤버를 채워 준다. 그래서 직접 정의한 함수에서는 특별한 처리가 필요한 멤버만 다루면 된다.
출처:
game_dev/cpp/chapter2/2025-06-08-cpp_2_12.md
📝 내 선택: ( )
Q2. 🔴 어려움
온라인 게임에서 플레이어 캐릭터의 이동은 기본적으로 아래 과정으로 처리된다.
① 클라이언트 → 서버 : 캐릭터를 조종하는 명령 전송
② 서버 : 캐릭터 이동 연산 수행
③ 서버 → 클라이언트 : 일정 시간(1/30 ~ 1/10초)마다 이동 정보 메시지 전송
④ 클라이언트 : 이동 정보를 받아 추측항법으로 위치를 부드럽게 갱신
(1) 이대로만 구현하면 플레이어는 답답하다고 느낀다. 왜 그런지, 위 ①~④ 중 어느 단계 사이에서 문제가 생기는지 짚어 설명하시오.
(2) 이를 해결하는 첫 번째 방향은 “사소한 것은 클라이언트에서” 다 — 클라이언트가 먼저 위치를 계산하고 서버에는 결과를 알려 주는 것이다. 그런데 이러면 치터 문제가 생긴다. 이를 막는 두 가지 방법이 있다.
- ㉠ 값 검증 방식은 클라이언트와 서버가 각각 무엇을 하는가?
- ㉡ 예측/보정 방식은 아래 세 단계로 이루어진다. 각 단계에서 무슨 일이 일어나는지 쓰시오.
클라이언트 ──① MyPlayer_Move()──▶ 서버
클라이언트 ──② MyPlayer_Move()──▶ 클라이언트 자신 (일단 이동)
서버 ──③ Player_Move()────▶ 클라이언트 (재조정)
(3) 예측/보정은 해킹을 막는 데 제일 좋지만 한계가 있다. 레이턴시가 얼마를 넘으면 무슨 일이 벌어지며, 어떤 조건에서 쓰는 것이 가장 좋은가?
(4) 두 번째 방향은 “일단 보여주고, 나중에 해결” 이다.
- ㉠ 이 방식의 세 단계를 쓰시오. (클라이언트가 명령을 보내는 것과 동시에 하는 일이 무엇인지가 드러나야 한다)
- ㉡ 레이턴시가 높을 때 플레이어 화면에서 어떤 순서로 연출이 보이게 되는가? 그리고 이 방식을 쓰는 게임의 예를 하나 드시오.
출처:
server/game_server/5/2026-02-14-game_server_5_3.md
📝 내 풀이:
풀이를 여기에 작성하세요
Q3. 🟢 쉬움
빈칸을 채우시오.
MongoDB API는 ① ___ (Binary JSON) 객체를 이용해 도큐먼트에 액세스한다. JSON과 같은 { "Key", "Value" } 구조지만 ② ___ 구조를 사용하기 때문에, 아래처럼 값 자리에 또 다른 도큐먼트를 중첩할 수 있다.
doc = new ① ___Document
{
{ "name", "John" },
{ "address", new ① ___Document
{
{ "City", "Seoul" },
{ "Street", "Nambu-street" }
}
}
};
게임 서버에서 명령을 실행하는 순서는 바깥에서 안쪽으로 좁혀 들어간다.
| 단계 | 코드 | 넘기는 매개변수 |
|---|---|---|
| 1. 연결 객체 생성 | client = new client("mongodb://localhost:27017") |
③ ___ |
| 2. 액세스 획득 | db = client["mydb"] |
④ ___ 이름 |
| 3. 액세스 객체 획득 | coll = db["mycollection"] |
⑤ ___ 이름 |
| 4. 도큐먼트 삽입 | coll.⑥ ___(doc) |
만들어 둔 도큐먼트 |
출처:
server/game_server/8/2026-03-14-game_server_8_9.md
📝 내 답: (빈칸 수에 맞게 작성하세요)
Q4. 🟡 보통 · 📌 오답노트 (2번째 복습)
다음 명제가 참(O)인지 거짓(X)인지 판단하라.
OSI 2계층인 데이터 링크 계층은 LAN 안에서의 통신을 담당한다. 단말기마다 고유한 MAC 주소가 있고, 데이터는 헤더(송·수신자 주소)와 페이로드(실제 데이터)로 이루어진 프레임 단위로 오간다. 요즘 LAN은 대부분 별 위상이라 단말기들이 스위치 하나에 연결된다.
그런데 스위치 하나가 연결할 수 있는 단말기 수에는 한계가 있고, 단말기가 많아지면 고유한 MAC 주소를 관리하기도 어려워진다. 이 문제를 해결하려고 WAN이 등장하며, 여러 LAN 사이의 경로를 설정하는 것이 3계층 네트워크 계층의 라우터다.
다만 실제로는 같은 LAN 안의 두 단말기가 통신할 때도 스위치가 IP 주소를 보고 경로를 정한다. 스위치는 프레임의 MAC 주소를 IP 주소로 변환한 뒤 라우팅 테이블을 참조하므로, 2계층 장비라 해도 결국 3계층 정보 없이는 동작할 수 없다.
출처:
server/game_server/2/2025-06-30-game_server_2_1.md오답노트:wn-34e57a32· 2026-09-09 최초 오답 · 이번이 2번째 복습
📝 내 답: O / X
Q5. 🔴 어려움
private 상속에 대한 문제다.
(1) 아래 코드에서 eat(s)는 컴파일되지 않는다. 왜인가? 그리고 private 상속에서 기본 클래스로부터 물려받은 public 멤버는 파생 클래스에서 어떤 접근 지정자가 되는가? 이 두 사실을 묶어 private 상속의 의미를 한 문장으로 쓰시오.
class Person { ... };
class Student : private Person { ... };
void eat(const Person& p);
Person p;
Student s;
eat(p); // ✅
eat(s); // ❌ 컴파일 에러
(2) 아래 두 클래스의 크기를 비교하려 한다.
class Empty {}; // 비정적 데이터 멤버가 하나도 없는 공백 클래스
class HoldsAnInt_A { // 객체 합성
private:
int x;
Empty e;
};
class HoldsAnInt_B : private Empty { // private 상속
private:
int x;
};
- ㉠
sizeof(HoldsAnInt_A)는sizeof(int)와 어떤 관계이며, 왜 그런가? (C++의 어떤 규칙 때문에Empty e가 공간을 차지하는지, 그 공간이 어떻게 구성되는지) - ㉡
sizeof(HoldsAnInt_B)는sizeof(int)와 어떤 관계인가? 이 현상의 이름과, 이것이 적용되기 위한 조건을 쓰시오.
(3) 기본 원칙은 “할 수 있다면 객체 합성, 꼭 해야만 한다면 private 상속” 이다. private 상속을 써야만 하는 경우 세 가지를 쓰시오. (2)㉡이 그중 하나다.
출처:
game_dev/cpp/chapter6/2025-10-26-cpp_6_39.md
📝 내 풀이:
풀이를 여기에 작성하세요
Q6. 🟡 보통
프라우드넷에서 SendUserMessage()로 메시지를 보낼 때 전송 옵션은 RmiContext 구조체에 담아 넘긴다.
c->SendUserMessage(HostID_Server, RmiContext::ReliableSend, data, 100);
s->SendUserMessage(ClientHostID, RmiContext::UnreliableSend, data, 50);
받는 쪽은 아래 이벤트 함수로 처리한다.
c->OnReceiveUserMessage =
[...](HostID sender, const RmiContext& rmiContext,
uint8_t* payload, int payloadLength) { ... };
RmiContext와 수신 처리에 대한 설명으로 가장 올바른 것은?
- A.
RmiContext에 담기는 옵션은ReliableSend와UnreliableSend딱 두 가지뿐이다. 암호화나 압축이 필요하면 애플리케이션이data를 직접 가공한 뒤 넘겨야 한다. - B.
RmiContext에는 “오래된 메시지는 건너뛸지” 옵션이 있는데, 이것은 채팅처럼 순서가 중요한 데이터에 켜야 한다. 밀린 메시지를 건너뛰어야 최신 대화부터 표시할 수 있기 때문이다. - C.
RmiContext에는 reliable/unreliable 외에 암호화 여부, 압축 여부, 오래된 메시지는 건너뛸지 같은 옵션이 함께 담긴다. 오래된 메시지 건너뛰기는 위치 갱신처럼 최신 값만 의미 있는 데이터에 적합하다. 수신 콜백은sender(누가),rmiContext(어떤 방식으로),payload·payloadLength(무엇을 얼마나)를 받으므로, 받는 쪽도 그 메시지가 어떤 옵션으로 왔는지 알 수 있다. - D.
SendUserMessage()에 HostID 배열을 넘겨 여러 클라이언트에게 보낼 때는RmiContext가 무시되고 자동으로 Reliable이 강제된다. 다수 전송에서 일부만 못 받으면 상태가 어긋나기 때문이다.
출처:
server/game_server/6/2026-02-23-game_server_6_4.md
📝 내 선택: ( )
댓글남기기