如何通过C++面试:附带代码示例的经典问题
C++面试是开发者面临的最严峻挑战之一。这门语言将底层编程的强大功能与现代面向对象和模板范式相结合。要成功通过面试,不仅需要掌握语法,还要理解内存、编译器以及标准库的工作原理。本文将解析C++面试中最常被问及的10大问题,并附带详细解答与代码示例。
1. 什么是RAII?为什么需要它?
RAII(资源获取即初始化)是C++的核心编程范式之一。其本质是:资源(内存、文件、互斥锁)在对象的构造函数中获取,并在析构函数中释放。这确保了即使发生异常也能正确清理资源。
错误代码示例(未使用RAII):
void process() { int* ptr = new int(42); // ... 可能抛出异常的代码 delete ptr; // 若在delete前发生异常,会导致内存泄漏}使用RAII的示例(采用std::unique_ptr):
#include <memory>
void process() { std::unique_ptr<int> ptr = std::make_unique<int>(42); // ... 可能包含异常的代码 // 当ptr离开作用域时自动释放内存}问及此问题的原因:RAII是C++安全资源管理的基础。没有它,编写可靠代码将无从谈起。
2. 虚函数与纯虚函数有何区别?
虚函数(virtual)可以在派生类中被重写,但在基类中有默认实现。纯虚函数(= 0)在基类中无实现,并使该类成为抽象类——无法实例化该类的对象。
示例:
class Base {public: virtual void foo() { std::cout << "Base foo"; } // 虚函数 virtual void bar() = 0; // 纯虚函数};
class Derived : public Base {public: void foo() override { std::cout << "Derived foo"; } void bar() override { std::cout << "Derived bar"; }};追问:虚函数表(vtable)如何工作?编译器会为每个包含虚方法的类创建一张虚函数表。每个对象都包含一个指向该表的指针(vptr)。调用虚函数时,通过虚函数表实现动态分派。
3. C++中有哪些智能指针?何时使用它们?
C++11引入了三种智能指针:
- std::unique_ptr — 独占所有权。不可复制,只能移动。适用于单一所有者的资源管理。
- std::shared_ptr — 共享所有权。采用引用计数机制。适用于多个对象需要共享同一资源的情况。
- std::weak_ptr — 不拥有资源,但可观察shared_ptr。用于打破循环引用。
unique_ptr使用示例:
#include <memory>
class MyClass { /* ... */ };
void example() { auto ptr = std::make_unique<MyClass>(); // auto ptr2 = ptr; // 错误!不可复制 auto ptr3 = std::move(ptr); // 正确,移动操作}使用shared_ptr和weak_ptr防止循环引用示例:
struct Node { std::shared_ptr<Node> next; std::weak_ptr<Node> prev; // 使用weak_ptr避免循环引用};4. 什么是移动语义与std::move?
移动语义允许将资源从一个对象"移动"到另一个对象,而非复制。这对于临时对象或复制开销较大的情况(例如std::string或