【C/C++】构造函数与析构函数
📘 C++ 构造函数与析构函数详解笔记
🧠 为什么需要构造函数与析构函数?
在 C++ 中,对象创建和销毁过程如果仅靠手动赋值和清理非常容易出错。为此,语言提供了构造函数和析构函数:
- 构造函数:用于在对象创建时自动初始化成员变量或执行初始化逻辑(如打开文件、分配内存等)
- 析构函数:用于在对象生命周期结束时自动释放资源(如释放内存、关闭文件、断开连接等)
📌 构造和析构是实现 RAII(资源获取即初始化)思想的核心机制,使资源安全地绑定在对象生命周期内。
🧩 什么是构造函数?
构造函数(Constructor)是 C++ 中一种特殊的成员函数,它在对象创建时自动调用,用于对对象进行初始化。
✅ 特点:
- 与类同名
- 没有返回类型(包括
void
) - 可以重载(多个构造函数)
- 可以带参数,也可以无参数(默认构造)
🧪 示例:普通构造函数
class MyClass {
public:int a;double b;// 构造函数定义MyClass(int x, double y) {a = x;b = y;}
};int main() {MyClass obj(10, 3.14); // 自动调用构造函数
}
🎯 构造函数初始化列表
构造函数除了可以在函数体中赋值,还可以使用“初始化列表”来初始化成员变量。
✅ 语法:
ClassName(参数) : 成员1(值1), 成员2(值2) { }
✅ 示例:
class MyClass {
private:int a;double b;public:MyClass(int x, double y) : a(x), b(y) {std::cout << "使用初始化列表初始化" << std::endl;}
};
✅ 使用初始化列表的优势:
- 更高效(尤其是
const
或引用类型成员) - 保证初始化顺序与声明顺序一致
- 对某些必须在初始化时赋值的成员(如
const
)是唯一方式
🧩 什么是析构函数?
析构函数(Destructor)是对象销毁前自动调用的特殊函数,用于释放资源。
✅ 特点:
- 函数名前加
~
- 没有参数、不能重载
- 没有返回值
✅ 示例:
class MyClass {
public:MyClass() {std::cout << "构造函数调用" << std::endl;}~MyClass() {std::cout << "析构函数调用" << std::endl;}
};int main() {MyClass obj; // 自动调用构造函数
} // 程序结束前自动调用析构函数
🛠 构造 & 析构的调用顺序
📚 单个对象:
MyClass obj;
// 调用顺序:构造函数 → (使用) → 析构函数
📚 数组对象:
MyClass arr[3];
// 先调用构造函数 3 次 → 最后调用析构函数 3 次(逆序)
🔒 特殊成员变量:const
和 &
引用
必须使用构造函数初始化列表来初始化:
class Sample {const int ci;int& ref;public:Sample(int x, int& y) : ci(x), ref(y) {}
};
🧠 默认构造函数与全缺省构造函数
✅ 默认构造函数:
class A {
public:A() {} // 无参构造函数
};
✅ 全缺省构造函数:
class A {
public:A(int x = 0, double y = 0.0) {// 参数都有默认值 → 也可视为无参构造使用}
};A a1; // OK,使用默认参数
A a2(3, 1.5); // OK,显式调用
📎 拓展:构造函数链表(调用其他构造函数)
从 C++11 起,可以在一个构造函数中调用另一个构造函数,这被称为构造函数委托:
class MyClass {int a, b;public:MyClass() : MyClass(0, 0) {} // 委托给有参构造函数MyClass(int x, int y) : a(x), b(y) {std::cout << "a = " << a << ", b = " << b << std::endl;}
};
🧼 小结
概念 | 构造函数 | 析构函数 |
---|---|---|
调用时机 | 创建对象 | 销毁对象 |
可否重载 | ✅ 是 | ❌ 否 |
是否带参数 | ✅ 可选 | ❌ 不可 |
特殊写法 | 初始化列表、委托构造 | 无 |
💡 小技巧:当类中含有指针成员、资源句柄、文件描述符等时,务必在析构函数中释放资源,防止内存泄漏。
📎 拓展阅读
- 构造函数的隐式调用和拷贝构造函数
- 析构函数中的虚函数(虚析构)适用于继承
- RAII(资源获取即初始化)思想