如何通过C++面试:高级别热门问题
\n\n中高级C++开发人员的面试不仅仅是检查语法。面试官希望看到对语言内部机制的深入理解,以及处理内存、模板和多线程的能力。在本文中,我们整理了C++高级别面试中最常见和最复杂的问题。每个问题都附有解释和代码示例。
\n\n1. 智能指针与RAII
\n\n关于智能指针的问题是经典问题。期望您不仅能说出std::unique_ptr、std::shared_ptr和std::weak_ptr,还能解释它们的内部机制以及何时使用哪一个。
典型问题:unique_ptr和shared_ptr有什么区别?shared_ptr中的引用计数是如何工作的?为什么需要weak_ptr?
答案:std::unique_ptr是资源的独占所有权。它不能被复制,只能被移动(移动语义)。std::shared_ptr使用引用计数来实现共享所有权。当计数降至零时,对象被删除。std::weak_ptr是一个“观察者”,它不会增加引用计数。它用于防止循环依赖(例如,在图或树中)。
#include <memory>\n#include <iostream>\n\nstruct Resource {\n Resource() { std::cout << "Resource acquired\\n"; }\n ~Resource() { std::cout << "Resource released\\n"; }\n};\n\nint main() {\n // unique_ptr\n std::unique_ptr<Resource> ptr1 = std::make_unique<Resource>();\n // std::unique_ptr<Resource> ptr2 = ptr1; // 编译错误 - 禁止复制\n std::unique_ptr<Resource> ptr2 = std::move(ptr1); // 允许移动\n\n // shared_ptr\n std::shared_ptr<Resource> sptr1 = std::make_shared<Resource>();\n std::shared_ptr<Resource> sptr2 = sptr1; // 允许复制,计数 = 2\n\n // weak_ptr\n std::weak_ptr<Resource> wptr = sptr1; // 计数不增加\n if (auto locked = wptr.lock()) {\n std::cout << "Resource is still alive\\n";\n }\n\n return 0;\n}\n\n附加问题:如何实现自己的SharedPtr?这里重要的是提到RAII(资源获取即初始化)——一种在构造函数中获取资源、在析构函数中释放资源的原则。
2. 虚析构函数与虚函数表(vtable)
\n\n这个问题考察对多态性和C++中虚函数机制的理解。
\n\n典型问题:为什么带有虚函数的基类必须要有虚析构函数?vtable是如何工作的?
\n\n答案:如果基类的析构函数不是虚函数,那么当通过基类指针删除派生类对象时,只会调用基类的析构函数。这将导致派生类分配的资源泄漏。
\n\n每个至少有一个虚函数的类都包含一个静态表(vtable)。表中存储了指向虚函数实现的指针。该类的每个对象都有一个隐藏指针(vptr),指向其类的vtable。虚函数的调用通过双重间接进行:对象 → vptr → vtable → 函数。与普通调用相比,这增加了一些开销。
\n\n#include <iostream>\n\nclass Base {\npublic:\n virtual void show() { std::cout << "Base\\n"; }\n virtual ~Base() = default; // 虚析构函数\n};\n\nclass Derived : public Base {\npublic:\n void show() override { std::cout << "Deriv