数码视讯 C++开发 一面

1. C++ 多态

答案:C++ 多态分编译时多态和运行时多态。编译时多态主要是函数重载、模板,运行时多态主要是虚函数。面试里一般问的还是运行时多态,也就是基类指针或者引用指向子类对象,调用重写后的函数。它的核心价值是接口统一、实现可替换,在客户端开发里像渲染对象、组件系统、资源加载器这类设计都很常见。多态成立的前提一般是继承、虚函数重写、父类指针或引用调用。

代码:

#include <iostream>
using namespace std;

class Base {
public:
    virtual void draw() { cout << "Base draw" << endl; }
    virtual ~Base() {}
};

class Sprite : public Base {
public:
    void draw() override { cout << "Sprite draw" << endl; }
};

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

2. 计算机怎么存整数,补码讲一下,-1 怎么存,浮点数怎么存

答案:整数在计算机里本质上都是二进制存储。对于有符号整数,现代计算机基本都使用补码。补码的好处是把加减法统一了,硬件实现简单,而且零只有一种表示。正数的补码就是它本身,负数的补码是对应正数按位取反再加一。比如 8 位下,100000001,那 -1 的补码就是 11111111。浮点数一般按 IEEE 754 标准存,分成符号位、指数位、尾数位。像 float 通常是 32 位,double 通常是 64 位。浮点数不是精确存十进制小数,所以会有精度误差,这也是为什么 0.1 + 0.2 不一定严格等于 0.3

3. 具体讲讲虚函数

答案:虚函数是 C++ 实现运行时多态的核心机制。一个类里只要有虚函数,编译器通常就会为这个类生成虚函数表,对象里会有一个虚表指针。当通过父类指针调用虚函数时,程序不是在编译期就确定调用哪个函数,而是运行时根据对象真实类型去虚表里查找。虚函数最常见的两个考点,一个是多态调用,另一个是虚析构。只要类要被当成基类使用,析构函数通常就应该写成虚函数,不然通过基类指针释放子类对象时可能析构不完整。另外构造函数里虽然能写虚函数调用,但那时候对象还没完全构造成子类语义,所以不会表现出完整的多态行为。

代码:

#include <iostream>
using namespace std;

class Base {
public:
    virtual void func() { cout << "Base::func" << endl; }
    virtual ~Base() { cout << "Base dtor" << endl; }
};

class Derived : public Base {
public:
    void func() override { cout << "Derived::func" << endl; }
    ~Derived() { cout << "Derived dtor" << endl; }
};

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

4. 智能指针,什么情况都能用智能指针吗

答案:常见智能指针有 unique_ptrshared_ptrweak_ptrunique_ptr 表示独占所有权,shared_ptr 表示共享所有权,weak_ptr 主要是配合 shared_ptr 解决循环引用。但智能指针不是任何场景都能无脑用。如果资源所有权非常明确,用 unique_ptr 很合适;如果对象被多个地方共同持有,才考虑 shared_ptr;如果只是观察者,不想影响生命周期,就用 weak_ptr。一些场景下并不适合,比如对象生命周期由引擎统一管理、跨 DLL 边界释放规则不一致、或者性能特别敏感的高频小对象场景,滥用 shared_ptr 反而会带来额外开销。所以核心不是“能不能用”,而是“所有权模型和生命周期是否适合用”。

5. vector 扩容机制

答案:vector 的底层是连续内存。容量不够时会申请一块更大的新内存,然后把旧数据搬过去,再释放旧内存。扩容倍数标准库实现不完全一样,常见是 1.5 倍或者 2 倍增长,所以 push_back 的均摊复杂度是 O(1),但某一次扩容本身可能是 O(n)。扩容会导致原有迭代器、指针、引用失效,这个在项目里很容易踩坑。如果提前知道大概要放多少元素,最好先 reserve,这样能减少扩容次数和内存搬迁成本。

代码:

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

int main() {
    vector<int> v;
    cout << "size=" << v.size() << " cap=" << v.capacity() << endl;

    for (int i = 0; i < 10; ++i) {
        v.push_back(i);
        cout << "push " << i
             << ", size=" << v.size()
             << ", cap=" << v.capacity() << endl;
    }
    return 0;
}

6. 熟悉的排序算法,快排什么时候退化为 O(n²),怎么优化

答案:常见排序算法像冒泡、选择、插入、归并、快排、堆排我都比较熟。工程里如果问得稍微深入一

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

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

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

全部评论
最后通过了吗
点赞 回复 分享
发布于 昨天 23:13 北京

相关推荐

评论
点赞
2
分享

创作者周榜

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