C++中构造函数和析构函数
在C++面试中,构造函数和析构函数是高频考点。以下是常见的面试题及其解析,帮助你系统掌握相关知识点:
一、基础概念题
1. 什么是构造函数和析构函数?它们的作用是什么?
- 构造函数:在对象创建时自动调用,用于初始化对象成员。
- 析构函数:在对象销毁时自动调用,用于释放资源(如内存、文件句柄等)。
- 关键区别:构造函数可重载,析构函数不能重载且无参数。
2. 如果没有显式定义构造函数和析构函数,会发生什么?
- 编译器会生成默认的无参构造函数和析构函数,但:
- 默认构造函数不会初始化内置类型(如
int、float)。 - 默认析构函数不会释放动态分配的资源(如
new分配的内存)。
- 默认构造函数不会初始化内置类型(如
二、构造函数相关题
3. 什么是拷贝构造函数?什么时候会被调用?
- 定义:用同类的另一个对象初始化新对象。
class MyClass { public: MyClass(const MyClass& other) { /* 拷贝逻辑 */ } }; - 调用场景:
- 对象直接初始化:
MyClass obj2 = obj1; - 函数传参(按值传递):
void func(MyClass obj) - 函数返回对象(按值返回时可能触发,取决于编译器优化)。
- 对象直接初始化:
4. 什么是移动构造函数(C++11)?它与拷贝构造函数的区别?
- 移动构造函数:通过“窃取”临时对象(右值)的资源来初始化新对象,避免深拷贝。
MyClass(MyClass&& other) noexcept { ptr = other.ptr; // 转移资源 other.ptr = nullptr; } - 区别:
- 拷贝构造函数保留原对象,移动构造函数使原对象处于有效但未定义状态。
5. 构造函数能否是虚函数?为什么?
- 不能:构造函数调用时对象尚未完全创建,虚函数表(vtable)未初始化,无法实现多态。
6. 构造函数抛出异常会导致什么问题?如何解决?
- 问题:对象构造不完整,但析构函数不会被调用,可能导致资源泄漏。
- 解决:
- 使用智能指针(如
std::unique_ptr)管理资源。 - 在构造函数内捕获异常并清理已分配的资源。
- 使用智能指针(如
三、析构函数相关题
7. 析构函数能否抛出异常?为什么?
- 不建议:如果析构函数抛出异常且未被捕获,程序可能直接终止(
std::terminate)。 - 最佳实践:在析构函数中处理所有异常,避免抛出。
8. 为什么基类的析构函数需要声明为虚函数?
- 原因:若派生类对象通过基类指针删除,非虚析构函数会导致派生类的析构函数未被调用,引发资源泄漏。
- 示例:
class Base { public: virtual ~Base() {} // 虚析构函数 }; class Derived : public Base { ~Derived() { /* 清理派生类资源 */ } }; Base* ptr = new Derived(); delete ptr; // 正确调用派生类析构函数
9. 什么是“虚析构函数”的必要性?举例说明。
- 场景:多态基类中,若未定义虚析构函数,通过基类指针删除派生类对象会导致未定义行为。
- 错误示例:
class Base { ~Base() {} }; // 非虚析构函数 delete new Derived(); // 派生类资源泄漏!
四、综合应用题
10. 以下代码的输出是什么?分析原因。
class Test {
public:
Test() { cout << "Constructor\n"; }
~Test() { cout << "Destructor\n"; }
};
void func() { Test t; }
int main() { func(); }
- 输出:
Constructor Destructor - 解析:
t是局部对象,函数结束时析构。
11. 以下代码有什么问题?如何修正?
class Resource {
int* data;
public:
Resource() { data = new int[100]; }
~Resource() { delete data; } // 错误!
};
- 问题:
new[]应用delete[]释放,否则行为未定义。 - 修正:
~Resource() { delete[] data; }
12. 实现一个单例类,要求线程安全(C++11以后)。
class Singleton {
private:
static Singleton* instance;
Singleton() {} // 私有构造函数
public:
Singleton(const Singleton&) = delete; // 禁用拷贝
static Singleton* getInstance() {
static Singleton inst; // C++11保证线程安全
return &inst;
}
};
五、高级问题
13. 什么是RAII?举例说明其在构造函数/析构函数中的应用。
- RAII(Resource Acquisition Is Initialization):资源在构造函数中获取,在析构函数中释放。
- 示例:
std::fstream在析构时自动关闭文件。
14. 如何防止对象被拷贝或赋值?
- C++11:
class NonCopyable { public: NonCopyable(const NonCopyable&) = delete; NonCopyable& operator=(const NonCopyable&) = delete; };
15. 解释“三/五法则”(Rule of Three/Five)。
- Rule of Three:若需自定义析构函数、拷贝构造函数或拷贝赋值运算符,通常需要同时定义这三者。
- Rule of Five(C++11):增加移动构造函数和移动赋值运算符。
总结
- 构造函数:关注重载、默认/拷贝/移动构造、初始化列表。
- 析构函数:重点在虚析构函数、资源释放、异常安全。
- 高频考点:RAII、Rule of Three/Five、深拷贝 vs 浅拷贝。
Do not communicate by sharing memory; instead, share memory by communicating.

浙公网安备 33010602011771号