C/C++ 笔试题与核心考点解析(嵌入式方向)
一、类与构造函数
1. 构造函数的调用方式
-
显式调用(Explicit)
cppName n1 = Name(40); // 等号 + 构造函数
-
隐式调用(Implicit)
cppName n2(40); // 类名后跟参数
⚠️ 注意:Name n3 = 40;
也可能成立,等效于调用单参数构造函数,但如果构造函数被 explicit
修饰,则禁止这种隐式转换。
2. 类对象数组初始化
示例:
cpp
class Name {
public:
Name() { cout << "?"; } // 默认构造函数
Name(int n) { cout << "!"; } // 带参数构造函数
};
Name names[3] = { Name(40), Name(41) };
解析:
names[0]
→ 调用Name(40)
(显式调用带参构造函数)names[1]
→ 调用Name(41)
(显式调用带参构造函数)names[2]
→ 未给出参数 → 调用默认构造函数Name()
结果:输出 !!?
3. 默认构造函数的调用时机
- 当数组中的某些元素未显式初始化时,自动调用默认构造函数。
- 若类没有默认构造函数而数组需要用到它 → 编译错误。
二、继承与多态
1. 构造函数调用顺序
- 先调用 基类构造函数 ,再调用 派生类构造函数。
- 析构函数调用顺序相反:先调用派生类析构函数,再调用基类析构函数。
2. 虚析构函数的必要性
如果基类指针指向派生类对象并通过 delete
释放:
cpp
Base* p = new Derived();
delete p;
- 若基类析构函数不是虚函数 → 只会调用基类析构函数,造成派生类资源泄漏。
- 若基类析构函数是
virtual
→ 会正确调用派生类析构函数。
三、对象的生命周期
1. 匿名对象
cpp
Name(40);
- 匿名对象在语句结束时立即析构。
- 可用于临时对象初始化或函数返回值。
2. 构造函数 & 析构函数的打印规律
如果每个构造/析构函数中输出符号,可以看到调用顺序,常见考题会让你推导输出结果。
四、整数与内存表示
1. 有符号数与无符号数
char
默认是 有符号数(范围 -128 ~ 127)。unsigned char
范围是0 ~ 255
。
2. 例题陷阱
cpp
char x = 0xFF;
printf("%d", x--);
分析:
0xFF = 11111111(二进制)
char
是有符号数,最高位 1 → 表示负数。11111111
(补码) =-1
。x--
→ 先使用x
的值(-1),再减一 → 所以输出-1
。
⚠️ 如果写成:
cpp
unsigned char x = 0xFF;
printf("%u", x);
则输出 255
。
五、核心总结
嵌入式 C/C++ 笔试常见考点:
- 构造函数调用方式:显式 vs 隐式。
- 类对象数组初始化:未初始化元素调用默认构造函数。
- 默认构造函数:必须存在,否则数组初始化可能失败。
- 继承构造与析构顺序:基类先构造,派生类先析构。
- 虚析构函数:保证通过基类指针正确释放派生类对象。
- 匿名对象:生命周期仅限当前语句。
- 有符号与无符号数 :注意
char
的符号属性。 - printf 格式符 :
%d
(有符号)、%u
(无符号),常见陷阱题。
👉 建议复习策略:
- 类与对象:重点是 构造函数/析构函数的调用顺序。
- 继承与多态:重点是 虚析构函数。
- 基础类型:重点是 整数的二进制表示与补码规则。