作为一名有十年经验的C++开发者,我深知类和对象是C++面试和实际开发中最核心的知识点。这份刷题集是我根据多年面试官经验和项目实战总结出来的精华题目,覆盖了从基础到高级的所有关键考察点。
这些题目不是随意挑选的,而是基于三个核心标准:
我将题目分为五个难度等级:
这是最基础的类和对象练习,重点考察:
关键实现技巧:
cpp复制class Complex {
private:
double real;
double imag;
public:
Complex(double r=0, double i=0) : real(r), imag(i) {}
// 运算符重载示例
Complex operator+(const Complex& other) const {
return Complex(real + other.real, imag + other.imag);
}
// 输出运算符重载
friend std::ostream& operator<<(std::ostream& os, const Complex& c);
};
注意:运算符重载时,要考虑返回值和参数是否为const引用,这是面试常考点。
这是考察深拷贝和资源管理的经典题目,必须掌握:
内存管理要点:
cpp复制class MyString {
char* data;
size_t length;
void free() { delete[] data; } // 统一的释放资源函数
public:
// 拷贝构造函数
MyString(const MyString& other) :
data(new char[other.length + 1]),
length(other.length)
{
std::copy(other.data, other.data + length + 1, data);
}
// 移动构造函数
MyString(MyString&& other) noexcept :
data(other.data),
length(other.length)
{
other.data = nullptr; // 必须置空,防止双重释放
other.length = 0;
}
~MyString() { free(); }
};
单例模式有多种实现方式,现代C++推荐Meyers' Singleton:
cpp复制class Singleton {
public:
static Singleton& getInstance() {
static Singleton instance; // 线程安全(C++11起)
return instance;
}
// 禁用拷贝和移动
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
private:
Singleton() = default;
~Singleton() = default;
};
关键点:C++11保证了局部静态变量的线程安全,这是最简洁高效的实现方式。
unique_ptr和shared_ptr的实现展示了C++资源管理的核心思想:
| 特性 | unique_ptr | shared_ptr |
|---|---|---|
| 所有权 | 独占 | 共享 |
| 拷贝语义 | 禁用(只允许移动) | 允许 |
| 实现复杂度 | 简单 | 复杂(需要引用计数) |
| 性能 | 高 | 较低(有原子操作开销) |
shared_ptr核心实现:
cpp复制template<typename T>
class shared_ptr {
T* ptr;
long* ref_count;
public:
explicit shared_ptr(T* p = nullptr) : ptr(p), ref_count(new long(1)) {}
~shared_ptr() {
if (--*ref_count == 0) {
delete ptr;
delete ref_count;
}
}
// 拷贝构造函数增加引用计数
shared_ptr(const shared_ptr& other) :
ptr(other.ptr), ref_count(other.ref_count)
{
++*ref_count;
}
};
vector是STL中最常用的容器,实现它需要掌握:
关键扩容逻辑:
cpp复制void reserve(size_t new_capacity) {
if (new_capacity <= capacity) return;
T* new_data = static_cast<T*>(operator new(new_capacity * sizeof(T)));
size_t i = 0;
try {
for (; i < size; ++i) {
new (&new_data[i]) T(std::move(data[i])); // 移动构造
}
} catch (...) {
for (size_t j = 0; j < i; ++j) {
new_data[j].~T(); // 已构造对象的析构
}
operator delete(new_data);
throw;
}
for (size_t i = 0; i < size; ++i) {
data[i].~T(); // 原对象的析构
}
operator delete(data);
data = new_data;
capacity = new_capacity;
}
迭代器是STL设计的核心,实现要点:
示例框架:
cpp复制template<typename T>
class Vector {
T* data;
size_t size;
size_t capacity;
public:
class iterator {
T* ptr;
public:
explicit iterator(T* p) : ptr(p) {}
// 实现各种迭代器操作...
};
iterator begin() { return iterator(data); }
iterator end() { return iterator(data + size); }
// const迭代器版本...
};
根据你的目标,我推荐不同的刷题顺序:
校招/初级岗位(1-3周)
中高级岗位(1-3个月)
| 问题现象 | 原因分析 | 解决方案 |
|---|---|---|
| 程序崩溃(访问无效内存) | 浅拷贝导致双重释放 | 实现深拷贝 |
| 内存泄漏 | 未正确释放资源 | 遵循RAII原则 |
| 野指针 | 指针未置空 | 移动操作后置空原指针 |
| 访问越界 | 未检查边界 | 添加边界检查逻辑 |
线程安全计数器示例:
cpp复制class ThreadSafeCounter {
mutable std::mutex mtx;
int count = 0;
public:
void increment() {
std::lock_guard<std::mutex> lock(mtx);
++count;
}
int get() const {
std::lock_guard<std::mutex> lock(mtx);
return count;
}
};
在实际项目中,类和对象的设计有几个关键原则:
我在实现字符串类时踩过的坑:
一个实用的调试技巧:在析构函数和关键操作中添加日志输出,可以清晰跟踪对象的生命周期和资源管理情况。