快手 软件开发-C++ 一面

1. 自我介绍

2. TCP 三次握手过程是什么,为什么一定要三次

答案:TCP 三次握手主要是为了建立可靠连接,并同步双方的初始序列号。第一次,客户端发送 SYN 给服务端,表示自己想建立连接,并带上客户端初始序列号。第二次,服务端收到后回复 SYN + ACK,既确认客户端的 SYN,也发送自己的初始序列号。第三次,客户端再回复 ACK,确认服务端的 SYN,双方进入 established 状态。

为什么不是两次,主要是为了确认双方的收发能力都正常。如果只有两次,服务端只能确认客户端能发、自己能收,但不能确认客户端能收、自己能发。另外三次握手也能避免历史重复连接请求导致服务端误建立连接。

3. TCP 四次挥手过程,为什么 TIME_WAIT 要等 2MSL

答案:TCP 断开连接通常是四次挥手。主动关闭方先发送 FIN,表示自己不再发送数据;被动关闭方回复 ACK。之后被动关闭方如果也没有数据要发了,再发送 FIN,主动关闭方回复 ACK。之所以通常是四次,是因为 TCP 是全双工的,一方关闭发送方向,不代表另一方也马上关闭发送方向。

TIME_WAIT 出现在主动关闭方,等待 2MSL 主要有两个原因。第一个是确保最后一个 ACK 能让对方收到,如果对方没收到 ACK,会重发 FIN,主动关闭方还能再次回复。第二个是让旧连接中的延迟报文在网络中自然消失,避免污染后续使用相同四元组的新连接。

4. UDP 和 TCP 的区别

答案:TCP 是面向连接的可靠字节流协议,提供确认重传、顺序保证、流量控制和拥塞控制,适合文件传输、登录、支付、接口请求这类对可靠性要求高的场景。UDP 是无连接的报文协议,不保证可靠、不保证顺序,也不保证不重复,但头部开销小、延迟低,适合直播、实时音视频、游戏同步、埋点上报等场景。

TCP 传输的是字节流,需要应用层自己处理粘包拆包;UDP 保留报文边界,但单个报文过大可能会被分片,丢包概率也会增加。所以选择 TCP 还是 UDP,不是看哪个更高级,而是看业务更关心可靠性还是实时性。

5. TCP 粘包和拆包是什么,怎么解决

答案:TCP 是字节流协议,不会帮应用层保留消息边界。发送端连续发送两条消息,接收端可能一次读到两条,也可能只读到半条,这就是粘包和拆包问题。解决方式一般是在应用层设计协议,比如固定长度、分隔符、消息头加消息体长度。工程里更常用的是消息头里带长度字段,接收端先读够头部,再根据长度读完整消息体。

代码:

#include <cstdint>
#include <string>
using namespace std;

#pragma pack(push, 1)
struct MsgHeader {
    uint32_t len;   // body 长度
    uint16_t type;  // 消息类型
};
#pragma pack(pop)

struct Packet {
    MsgHeader header;
    string body;
};

6. HTTP 和 HTTPS 的区别,HTTPS 加密过程怎么理解

答案:HTTP 是明文传输,数据在网络中可能被窃听、篡改或伪造。HTTPS 是在 HTTP 和 TCP 之间加了一层 TLS,用来保证身份认证、数据加密和完整性校验。HTTPS 不是全程都用非对称加密。非对称加密主要用于身份认证和密钥协商,真正传输业务数据时一般使用对称加密,因为对称加密性能更好。

TLS 握手时,客户端会校验证书是否合法,确认服务端身份,然后双方协商会话密钥。后续 HTTP 数据会用这个会话密钥进行对称加密传输。所以 HTTPS 解决的不只是“加密”,还包括“我访问的是不是真的目标服务器”。

7. CA 证书申请和校验流程了解吗

答案:CA 证书本质上是由可信 CA 机构签发的服务器身份证明。服务器申请证书时,一般要生成公私钥对和 CSR 文件,把域名、组织信息、公钥等提交给 CA。CA 会验证域名或组织身份,验证通过后用 CA 私钥对证书内容签名,签发证书。

客户端访问 HTTPS 网站时,会拿到服务器证书,然后用本地信任的 CA 根证书或中间证书去验证签名链。如果证书过期、域名不匹配、签名链不可信,浏览器或客户端就会提示风险。这里比较关键的是:证书里放的是公钥和身份信息,私钥必须只保存在服务器侧,不能泄露。

8. C++ 面向对象的三大特性

答案:C++ 面向对象三大特性是封装、继承和多态。封装是把数据和操作数据的方法组织在一起,对外暴露稳定接口,隐藏内部实现。继承是子类复用和扩展父类能力,但继承层次不能太深,否则维护成本会变高。多态是通过基类指针或引用调用虚函数,在运行时根据真实对象类型执行不同逻辑。

在短视频热点事件实时聚合系统里,可以把不同事件处理器抽象成统一接口,比如点赞事件、评论事件、转发事件都实现同一个 process 方法,调度器只依赖抽象类。

代码:

#include <iostream>
#include <memory>
using namespace std;

class EventHandler {
public:
    virtual void process() = 0;
    virtual ~EventHandler() = default;
};

class LikeHandler : public EventHandler {
public:
    void process() override {
        cout << "process like event\n";
    }
};

class CommentHandler : public EventHandler {
public:
    void process() override {
        cout << "process comment event\n";
    }
};

int main() {
    unique_ptr<EventHandler> h = make_unique<LikeHandler>();
    h->process();
    return 0;
}

9. 虚函数大致是怎么实现的

答案:C++ 的运行时多态通常依赖虚函数表和虚表指针实现。如果一个类里有虚函数,编译器一般会为这个类生成一张虚函数表,表里存放虚函数地址。对象内部会有一个虚表指针,指向对应类的虚函数表。通过基类指针调用虚函数时,程序会先根据对象里的虚表指针找到虚表,再根据函数偏移找到真正要调用的函数。

需要注意的是,虚函数会带来对象体积增加和间接调用开销。如果类作为基类使用,析构函数通常要声明为虚析构,否则通过基类指针删除派生类对象时可能只调用基类析构,导致资源泄漏。

代码:

#include <iostream>
using namespace std;

class Base {
public:
    virtual void run()

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

C++ 常考面试题总结 文章被收录于专栏

本专栏系统梳理C++方向, 大中厂高频高频面试考点 , 内容皆来自真实面试经历,从基础语法、内存管理、STL与设计模式,到操作系统与项目实战,结合真实面试题深度解析,帮助开发者高效查漏补缺,提升技术理解与面试通过率,打造扎实的C++工程能力.

全部评论

相关推荐

点赞 评论 收藏
分享
评论
点赞
1
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务