bilibili C++开发 一面

1. C++11 / 17 / 20 比较有意思的新特性

C++11 最重要的是把现代 C++ 的写法真正建立起来了,比如 autodecltype、右值引用、移动语义、lambda、智能指针、线程库这些。lambda 很有意思,因为它把函数对象的使用门槛降得很低,很多回调、排序、自定义策略都能直接在调用点写掉。C++17 我会比较关注结构化绑定、if constexproptionalvariantstring_view,这些东西很实用,既提升表达力,也减少不必要的拷贝。C++20 更有代表性的像 concept、ranges、coroutine。concept 让模板约束更清晰,ranges 让算法和容器组合更自然,coroutine 则对异步流程表达很友好。如果说“有趣”,我会优先聊 lambda、移动语义和 coroutine,因为这几个对代码风格和工程写法影响都很大。

代码:

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main() {
    vector<int> v = {4, 2, 5, 1, 3};
    sort(v.begin(), v.end(), [](int a, int b) {
        return a < b;
    });

    for (auto x : v) {
        cout << x << " ";
    }
    return 0;
}

2. auto 和 decltype 的区别

auto 更偏向“让编译器帮我推导这个变量的类型”,通常用于定义变量时根据初始化表达式来推导类型。decltype 更偏向“告诉我这个表达式的类型到底是什么”,它不一定要求真的创建对象,更适合在模板、返回值推导、类型萃取里用。两者都和类型推导有关,但使用场景不一样。auto 主要解决写起来太啰嗦的问题,decltype 更像是一个观察和提取类型的工具。如果在复杂泛型代码里,decltype 会比 auto 更精准,因为它保留表达式类型特征的能力更强。

代码:

#include <iostream>
using namespace std;

int main() {
    int x = 10;
    auto a = x;          // int
    decltype(x) b = 20;  // int
    decltype((x)) c = x; // int&

    c = 30;
    cout << x << endl;   // 30
    return 0;
}

3. const 的作用,const 修饰成员函数的作用,如果要修改该怎么办

const 的核心作用是表达“这个值或这个接口不应该修改对象状态”。修饰变量时表示只读语义;修饰指针时可以约束“指向内容不可改”或者“指针本身不可改”;修饰成员函数时,表示这个函数承诺不修改对象的逻辑状态,所以 this 会变成指向常量对象的指针。成员函数后面加 const 很重要,因为它不仅能增强接口约束,还能让常对象也能调用这个函数。如果确实有个别成员需要在 const 函数里修改,比如缓存命中次数、延迟初始化标记这类不影响对象对外逻辑语义的字段,可以用 mutable

代码:

#include <iostream>
using namespace std;

class Demo {
public:
    int get() const {
        ++cnt_;
        return val_;
    }
private:
    int val_ = 10;
    mutable int cnt_ = 0;
};

int main() {
    const Demo d;
    cout << d.get() << endl;
    return 0;
}

4. static 的作用

static 在 C++ 里不是单一语义。修饰局部变量时,它改变的是存储期,变量不再随着函数退出销毁,而是整个程序运行期间都存在,但作用域还是局部;修饰全局变量或函数时,它改变的是链接属性,让符号只在当前编译单元内可见;修饰类成员变量时,它表示这个成员属于类本身,而不属于具体某个对象。所以理解 static 时最好把“生命周期”“作用域”“链接可见性”“归属关系”这几个概念分开看,不要混在一起。

5. C++ 多态的实现机制,虚表指针怎么理解

答案:运行时多态主要依赖继承、虚函数和基类指针或引用。底层上,编译器通常会为有虚函数的类生成一张虚函数表,对象里会有一个隐藏的虚表指针 vptr 指向这张表。调用虚函数时,不是编译期直接决定调用地址,而是运行时通过对象里的 vptr 找到对应函数入口。这也是为什么同一个基类接口,在不同派生类对象上会表现出不同实现。虚表一般在编译期生成,虚表指针则随着对象一起存在于对象内存布局中。

代码:

#include <iostream>
using namespace std;

class Base {
public:
    virtual void print() { cout << "Base\n"; }
    virtual ~Base() = default;
};

class Derived : public Base {
public:
    void print() override { cout << "Derived\n"; }
};

int main() {
    Base* p = new Derived();
    p->print();
    delete p;
    return 0;
}

6. 可以用基类对象接收派生类对象来实现多态吗

答案:不能真正实现运行时多态。如果是“基类对象 = 派生类对象”,会发生对象切片。也就是说,派生类中超出基类的那部分会被截掉,只保留基类子对象部分。这样之后通过这个基类对象调用函数,本质上已经不是在操作完整的派生类对象了。真正的运行时多态需要基类指针或者基类引用去绑定派生类对象,这样动态类型信息才不会丢。所以面试里如果问这个点,关键就是答出“对象切片”。

7. 析构函数为什么通常要求写成虚析构,如果不是虚的为什么会出问题

答案:如果一个类会作为基类被多态使用,也就是可能通过基类指针指向派生类对象并释放,那么析构函数通常必

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

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

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

全部评论

相关推荐

03-14 15:23
门头沟学院 Java
点赞 评论 收藏
分享
03-13 18:31
已编辑
门头沟学院 Java
就这个八股爽,进入八股舒适区了八股多来点3.12上午面,3.13下午通知已过(正式系统好像还没开?)1.&nbsp;mysql事物四大特性,有哪些隔离级别,你用的引擎默认隔离级别是什么?为什么?2.&nbsp;mvcc是什么3.&nbsp;索引用的什么,为什么是b+树,不用哈希或者b树红黑树4.知道二阶段提交吗?5.&nbsp;undolog&nbsp;redolog和bin&nbsp;log都是干什么的?6.mysql的epoll知道吗(还真不知道)7.&nbsp;Redis有哪些数据结构?8.知道跳表吗?它的数据结构是什么样的?9.跳表查询时间复杂度,删除时间复杂度10.最快的情况下时间复杂度是什么?11.Red&nbsp;is的哨兵模式12.知道IO多路复用吗?13.&nbsp;知道用户态和内核态吗?14.&nbsp;线程池有哪些参数?15.&nbsp;遇到过线程池导致oom的情况吗?16.介绍一下tcp的三次握手和四次挥手17.&nbsp;为什么三次握手,如果只有两次会怎么样?为什么四次挥手?如果只有三次会怎么样18.&nbsp;知道tcp的信包吗?(没听过,说不知道,下来查了下可能是当时空耳了,应该是TCP的信道?)19.&nbsp;TCP的丢包重传和拥塞控制20.Mq如何确保消息不丢失?21.&nbsp;如何确保消息的幂等性不重复消费?22.&nbsp;如何保证的hive表到mysql同步的数据一致性?23.介绍一下es的倒排索引24.&nbsp;当时项目如何对es的索引进行优化的?25.&nbsp;为什么要用clickhouse,相对MySQL优势是什么?26.&nbsp;日常项目中AI用的多吗?主要是干什么?27.&nbsp;写项目中AI使用占比28.&nbsp;算法题:&nbsp;快速排序没有任何提示的编译器,和文本编辑器差不多,纯手敲……不过没硬性要求能运行,主要是看代码讲解代码,快速排序的时间复杂度,空间复杂度,最坏情况下的时间复杂度
多多miumiu:27届拼多多实习机会或看我主页&nbsp;https://careers.pddglobalhr.com/campus/intern?t=4OmKPVeX9a
查看29道真题和解析
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

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