面灵AI→

联想嵌入式软件一面:C++ 多态机制与 Linux、网络分层辨析

轮次
一面
时间
2026-09
来源
牛客网

《面试题目》

  1. 标准演进中哪些新增语言与库能力对现代 C++ 开发影响较大,实际项目中常用于解决哪些问题?
  2. 编译期决议与运行期决议的多态分别依赖哪些语言构造,二者在灵活性、运行时开销和适用场景上如何取舍?
  3. 同一接口在不同对象上呈现不同行为这一目标,在 C++ 中通常通过哪些语言机制落地,运行期分派依赖怎样的对象布局支持?
  4. 多态类的函数分派表一般如何组织,指向该表的指针通常位于对象内存的哪个区域,哪些因素会改变其具体布局?
  5. Linux 中用于探测路径存在性或访问权限的接口能完成哪些判断,为何检查结果与后续实际操作之间可能产生竞态窗口?
  6. 空字符、字符零和整数零在编码值、类型和典型使用场景上有哪些不同,C 字符串结尾为何依赖其中一种?
  7. 网络分层体系里各层通常有哪些代表协议,TCP/IP 模型与 OSI 参考模型的层次划分如何映射?

《参考解析》

  1. C++ 标准演进带来的能力:把影响分成三类答比较清楚——语言能力(移动语义与右值引用、auto 与结构化绑定、constexpr、概念、协程)、库能力(智能指针、optional/variant/string_view、filesystem、ranges、thread 与 jthread)、以及并发与内存模型(原子类型与内存序)。落到项目里,这些能力解决的是拷贝开销、资源生命周期、编译期计算和跨平台的文件与线程管理,举一个自己真用过的点比背清单有说服力。回答时注意别把它当成版本编年史,面试官问的是「对你的代码有什么改变」。
  2. 编译期与运行期多态:编译期多态靠模板、重载、CRTP 和 constexpr,调用点在编译期就确定,零运行开销,代价是代码膨胀、编译变慢、报错难读;运行期多态靠继承加虚函数,能跨编译单元扩展、可以在运行期替换实现,代价是虚表指针、间接跳转和无法内联。选型判据可以落在「类型集合在编译期是否已知」:数值与容器这类性能敏感的通用代码走编译期,插件式或需要运行期换实现的走运行期。嵌入式场景还要补一句:多数项目会关 RTTI 和异常,虚函数可以用但别滥用。
  3. 虚函数表与对象布局:有虚函数的类,每个对象里会有一个指向该虚函数表的指针,按照 Itanium C++ ABI 它通常位于对象起始处,表里按声明顺序存放虚函数地址;但标准并不规定这套布局,多继承会有多个指针、虚继承还会引入偏移量。加虚函数、改继承关系、改访问控制或换编译器版本,都可能改变具体布局。所以结论是:不要跨模块边界传多态对象、更不要手写结构体内存布局去对齐虚表,需要跨边界时用稳定的 C 接口或序列化。
  4. Linux 路径探测的竞态窗口:这类接口(access、stat)能判断路径是否存在、是否可读可写可执行、是不是目录或符号链接。竞态在于检查与后续 open 之间存在时间窗口——期间文件可能被替换、权限被改,或者攻击者用符号链接把路径指向别处,这就是典型的 TOCTOU。正确做法是不要「先检查再操作」,而是直接 open 再用 fstat 校验拿到的文件描述符,必要时加 O_NOFOLLOW、O_EXCL,或先以高权限打开再降权;检查结果只能当提示,不能当保证。
  5. 空字符、字符零与整数零:‘\0’ 是值为 0 的 char 类型字面量,‘\0’ 的编码值就是 0,和整数 0 数值相同但类型与含义完全不同;C 字符串用它做结尾哨兵,所以字符串内容里不能出现这个字节。C 字符串以 ‘\0’ 结尾是历史与实现的选择:函数靠扫描到零字节确定长度,带来的是 O(n) 求长和不能存二进制数据的限制。网络分层回答时把 OSI 七层与应用层、传输层、网络层、网络接口层做个映射,各层点名代表协议(HTTP/DNS、TCP/UDP、IP/ICMP、以太网/ARP),并说明分层的价值是每层只依赖下层提供的能力、可以独立替换与排障。