中兴通讯 C++开发一面总结
1. 自我介绍,说说你的项目经历和技术栈
回答框架:
- 教育背景和工作经验
- 熟悉的编程语言和技术栈
- 做过的项目类型和业务场景
- 项目中的角色和主要贡献
2. 你的项目中用到了哪些设计模式?举例说明应用场景
答案:
常用设计模式:
- 单例模式:场景:配置管理类、日志类、数据库连接池保证全局唯一实例
- 工厂模式:场景:创建不同类型的网络协议解析器解耦对象创建和使用
- 观察者模式:场景:Qt的信号槽机制事件通知、消息订阅
- 策略模式:场景:不同的数据压缩算法(gzip、lz4、snappy)运行时切换算法
- 装饰器模式:场景:给网络数据包添加加密、压缩等功能动态扩展功能
- 适配器模式:场景:适配不同版本的协议接口接口转换
实际案例:"我们的网管系统需要支持多种设备协议(SNMP、Telnet、SSH),用工厂模式创建不同的协议处理器。每种协议处理器实现统一的接口,业务层不需要关心具体协议类型。"
3. 如果软件界面有多个相同类型的控件需要同时响应,你会如何设计
答案:
方案一:信号槽统一处理:
// 所有按钮连接到同一个槽
for (int i = 0; i < 10; ++i) {
QPushButton* btn = new QPushButton(QString::number(i));
connect(btn, &QPushButton::clicked, this, &MainWindow::onButtonClicked);
}
void MainWindow::onButtonClicked() {
QPushButton* btn = qobject_cast<QPushButton*>(sender());
if (btn) {
qDebug() << "Button" << btn->text() << "clicked";
}
}
方案二:Lambda捕获索引:
for (int i = 0; i < 10; ++i) {
QPushButton* btn = new QPushButton(QString::number(i));
connect(btn, &QPushButton::clicked, [this, i]() {
handleButton(i);
});
}
方案三:QSignalMapper(Qt5之前):
QSignalMapper* mapper = new QSignalMapper(this);
for (int i = 0; i < 10; ++i) {
QPushButton* btn = new QPushButton(QString::number(i));
connect(btn, SIGNAL(clicked()), mapper, SLOT(map()));
mapper->setMapping(btn, i);
}
connect(mapper, SIGNAL(mapped(int)), this, SLOT(handleButton(int)));
方案四:事件过滤器:
for (int i = 0; i < 10; ++i) {
QPushButton* btn = new QPushButton(QString::number(i));
btn->installEventFilter(this);
}
bool MainWindow::eventFilter(QObject* obj, QEvent* event) {
if (event->type() == QEvent::MouseButtonPress) {
QPushButton* btn = qobject_cast<QPushButton*>(obj);
if (btn) {
// 统一处理
}
}
return QObject::eventFilter(obj, event);
}
4. 说说C++的红黑树,STL中哪些容器用了红黑树
答案:
红黑树特点:
- 自平衡二叉搜索树
- 每个节点有颜色(红或黑)
- 根节点是黑色
- 红色节点的子节点必须是黑色
- 从根到叶子的所有路径,黑色节点数量相同
性能:
- 查找、插入、删除:O(log n)
- 比AVL树平衡性差一点,但插入删除更快
STL容器:
- map:键值对,有序,底层红黑树
- set:集合,有序,去重,底层红黑树
- multimap:允许重复键的map
- multiset:允许重复元素的set
与unordered_map的区别:
- map:有序,O(log n),红黑树
- unordered_map:无序,O(1)平均,哈希表
使用场景:
- 需要有序:用map/set
- 需要范围查询:用map/set
- 只需要快速查找:用unordered_map/set
5. map和unordered_map的底层实现,哈希冲突如何解决
答案:
map:
- 底层:红黑树
- 有序:按key排序
- 时间复杂度:O(log n)
- 内存:每个节点有额外指针和颜色
unordered_map:
- 底层:哈希表
- 无序
- 时间复杂度:O(1)平均,O(n)最坏
- 内存:需要额外的桶数组
哈希冲突解决:
- 链地址法(C++ STL采用):每个桶是一个链表冲突的元素放到同一个链表查找时遍历链表
- 开放寻址法:线性探测:顺序查找下一个空位二次探测:按平方数探测双重哈希:用第二个哈希函数
负载因子:
- 元素数量 / 桶数量
- STL默认负载因子1.0
- 超过阈值会rehash(扩容)
性能优化:
- 预留空间:
reserve()避免频繁rehash - 自定义哈希函数:提高分布均匀性
- 选择合适的初始桶数量
6. 图的遍历方法有哪些?如何解决迷宫问题
答案:
图的遍历:
- 深度优先搜索(DFS):递归或栈实现一条路走到底,再回溯适合:路径搜索、连通性判断
- 广度优先搜索(BFS):队列实现逐层遍历适合:最短路径、层次遍历
迷宫问题(最短路径):
struct Point {
int x, y, dist;
};
int solveMaze(vector<vector<int>>& maze, Point start, Point end) {
int dx[] = {0, 0, 1, -1};
int dy[] = {1, -1, 0, 0};
queue<Point> q;
vector<vector<bool>> visited(maze.size(),
vector<bool>(maze[0].size(), false));
q.push({start.x, start.y, 0});
visited[start.x][start.y] = true;
while (!q.empty()) {
Point cur = q.front();
q.pop();
if (cur.x == end.x && cur.y == end.y) {
return cur.dist;
}
for (int i = 0; i < 4; ++i) {
int nx = cur.x + dx[i];
int ny = cur.y + dy[i];
if (nx >= 0 && nx < maze.size() &&
ny >= 0 && ny < maze[0].size() &&
maze[nx][ny] == 0 && !visited[nx][ny]) {
q.push({nx, ny, cur.dist + 1});
visited[nx][ny] = true;
}
}
}
return -1; // 无解
}
其他图算法:
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
C++八股文全集 文章被收录于专栏
本专栏系统梳理C++技术面试核心考点,涵盖语言基础、面向对象、内存管理、STL容器、模板编程及经典算法。从引用指针、虚函数表、智能指针等底层原理,到继承多态、运算符重载等OOP特性从const、static、inline等关键字辨析,到动态规划、KMP算法、并查集等手写实现。每个知识点以面试答题形式呈现,注重原理阐述而非冗长代码,帮助你快速构建完整知识体系,从容应对面试官提问,顺利拿下offer。
查看14道真题和解析
字节跳动公司福利 1371人发布