# C++ 基础摸底小测验（10 题，预计 10 分钟）

> 用途：验证 `docs/teaching/OUTLINE.md` §0 里"学员已掌握 C++ 基础语法与 OOP
> 概念"这条假设是否成立。建议在 **Day1 模块 B 开始前**（C++ 回顾环节之前）
> 发给学员，闭卷、不查资料，10 分钟内独立完成。
>
> 题型：选择题 + 代码阅读（判断输出/找 bug）+ 1 道简答，覆盖 Day1 回顾要点
> 涉及的引用、重载、构造析构顺序、虚函数多态、运算符重载、模板、STL、
> const、深浅拷贝九个知识点。

---

## 第 1 题（选择，30 秒）

下列关于"引用"和"指针"的说法，**错误**的是？

A. 引用必须在定义时初始化
B. 引用可以为 `nullptr`
C. 引用一旦绑定就不能再指向其他对象
D. 函数参数用引用可以避免拷贝开销

## 第 2 题（代码阅读，1 分钟）

```cpp
void f(int x)    { std::cout << "int " << x; }
void f(double x) { std::cout << "double " << x; }

int main() { f(3.0f); }
```

这段代码输出什么？

## 第 3 题（选择，30 秒）

关于虚函数，下列说法**正确**的是？

A. 基类析构函数不加 `virtual`，通过基类指针 `delete` 派生类对象一定不会有问题
B. 构造函数可以是虚函数
C. 纯虚函数所在的类不能被直接实例化
D. 派生类必须重写基类的每一个虚函数

## 第 4 题（代码阅读，1 分钟）

```cpp
class A { public: A(){ std::cout<<"A"; } ~A(){ std::cout<<"~A"; } };
class B : public A { public: B(){ std::cout<<"B"; } ~B(){ std::cout<<"~B"; } };

int main(){ B b; }
```

请写出输出的完整顺序。

## 第 5 题（找 bug，1.5 分钟）

```cpp
class Buffer {
    char* data;
public:
    Buffer(int n) { data = new char[n]; }
    ~Buffer() { delete[] data; }
};

void use() {
    Buffer a(10);
    Buffer b = a;   // 用 a 拷贝构造 b
}
```

`use()` 函数运行到结束时会发生什么问题？请说明原因。

## 第 6 题（选择，30 秒）

关于函数模板，下列说法**正确**的是？

A. 模板函数一旦定义，编译器就会为所有可能的类型生成代码
B. 编译器会根据调用时的实参类型自动推导模板参数，并生成对应的实例
C. 模板函数不能被重载
D. 调用模板函数时必须显式指定所有模板参数

## 第 7 题（代码阅读，1 分钟）

```cpp
std::vector<int> v = {3, 1, 4, 1, 5};
for (int x : v) {
    if (x % 2 == 0) std::cout << x;
}
```

这段代码输出什么？

## 第 8 题（选择，30 秒）

下列哪个函数声明表示"这个成员函数不会修改对象的成员变量"？

A. `void print()`
B. `void print() const`
C. `const void print()`
D. `void const print()`

## 第 9 题（代码阅读，1 分钟）

```cpp
class Point {
public:
    int x, y;
    Point operator+(const Point& other) const {
        return Point{x + other.x, y + other.y};
    }
};

Point p1{1, 2}, p2{3, 4};
Point p3 = p1 + p2;
std::cout << p3.x << "," << p3.y;
```

这段代码输出什么？

## 第 10 题（简答，1.5 分钟）

用一两句话说明"深拷贝"和"浅拷贝"的区别，以及为什么一个类里如果有指针成员、
又没有自己实现拷贝构造函数，可能会引发问题。

---

## 答案与评分（教师用，建议测验时不发给学员）

| 题号 | 答案 | 对应知识点 · 出处 |
|---|---|---|
| 1 | B（引用不能为空，这是它和指针的关键区别之一） | 引用的本质 · `p01/ch03/reference_essence.cpp` |
| 2 | `double 3`（`float` 到 `double` 是浮点提升，比 `float` 到 `int` 的转换更优先匹配 `f(double)`） | 函数重载决议 · `p01/ch03/function_overload_mechanism.cpp` |
| 3 | C（A 错——没有 virtual 析构会导致派生类部分不被析构；B 错——构造函数不能是虚函数；D 错——不重写就继承基类实现，纯虚函数才必须重写） | 虚函数与抽象类 · `p01/ch04/s08` |
| 4 | `A B ~B ~A`（先构造基类再构造派生类；析构顺序相反） | 继承中构造/析构顺序 · `p01/ch04/s07/inheritance_ctor_dtor_order.cpp` |
| 5 | 浅拷贝：`b` 的 `data` 和 `a` 的 `data` 指向同一块内存；函数结束时 `~Buffer()` 被调用两次，对同一块内存 `delete[]` 两次（double free），行为未定义/可能崩溃 | 深拷贝 vs 浅拷贝 · `p01/ch04/s03/deep_vs_shallow_copy.cpp` |
| 6 | B（模板是"按需实例化"，不是提前生成所有版本） | 函数模板 · `p01/ch05/function_template.cpp` |
| 7 | `4`（3,1,4,1,5 里只有 4 是偶数） | STL 容器与范围 for · `p01/ch09/s03/vector_iterator.cpp` |
| 8 | B（`const` 放在参数列表后面，修饰的是"this 指向的对象不可修改"） | const 成员函数 · `p01/ch04/s04/const_member_function.cpp` |
| 9 | `4,6`（`1+3=4`，`2+4=6`） | 运算符重载 · `p01/ch04/s06/overload_assignment.cpp` |
| 10 | 浅拷贝只复制指针本身（地址），深拷贝复制指针指向的内容；没有自定义拷贝构造函数时，编译器生成的默认拷贝构造函数是浅拷贝，两个对象的指针成员会指向同一块内存，析构时重复释放（double free）或修改一个对象的数据影响另一个对象 | 深拷贝 vs 浅拷贝 · `p01/ch04/s03/deep_vs_shallow_copy.cpp` |

### 评分建议

- **8–10 题正确**：具备 `OUTLINE.md` §0 假设的基础，按 Day1 模块 B 原定的
  "巡礼式回顾"节奏推进即可。
- **5–7 题正确**：部分薄弱点——对照上表找出学员集中出错的知识点（比如普遍
  在第 4/5 题失分，说明构造析构顺序和深浅拷贝没吃透），讲课时在对应知识点
  多花 5–10 分钟，其余部分维持原节奏。
- **0–4 题正确**：明显达不到"已掌握 C++ 基础语法与 OOP 概念"的假设——按
  `OUTLINE.md` §0 里的预案，Day1 模块 B 的讲授部分退回到语法讲解，练习任务
  保持不变但预期完成度应下调，不需要重排整个教案结构。

## 使用方式

- 建议纸质或线上表单均可，闭卷、不查资料、不讨论，10 分钟收卷；
- 只用于摸底分层，不计入 `docs/TRAINING_PLAN_2026.md` 的正式考核成绩；
- 大规模学员时可以只统计"每题正确率"而不用逐份细看，正确率低于 50% 的题
  对应知识点在 Day1 模块 B 里适当加时。
