1. 引言在 C 面向对象编程中构造函数和析构函数是类生命周期管理的核心机制。构造函数负责对象的初始化析构函数负责资源的清理与释放。理解并正确使用这两个特殊成员函数是写出健壮、无内存泄漏 C 程序的基础。2. 构造函数构造函数是一种特殊的成员函数在对象创建时自动调用用于初始化对象的成员变量、分配资源或执行必要的准备工作。构造函数的名字与类名相同且没有返回值类型。2.1 默认构造函数默认构造函数是不需要参数即可调用的构造函数。如果类中没有显式定义任何构造函数编译器会自动生成一个默认构造函数对内置类型成员的初始化行为是不确定的对类类型成员调用其默认构造函数此时自定义类型无默认构造函数时就会报错所以当没有默认构造函数时成员变量会走它定义的地方-初始化列表后续讲解。无参构造函数全缺省函数以及编译器自动生成的构造函数都是默认构造函数。class Student { public: Student() { name 未知; age 0; } private: std::string name; int age; }; int main() { Student s1; //这里的初始化不要在对象后面加上(),会分不清到底是实例化对象还是函数声明 return 0; }2.2 带参构造函数带参构造函数允许在创建对象时传入参数从而以不同的初始值构造对象。带参构造函数可以配合默认参数使用也可以使用初始化列表来高效初始化成员。class Student { public: Student(const std::string n, int a) : name(n) , age(a) //初始化列表后续讲解 {} private: std::string name; int age; };2.3 拷贝构造函数拷贝构造函数用于以同类型对象为蓝本创建新对象其第一个参数必须是同类对象的引用且其他变量均有默认值。当以值传递对象、返回对象或以已有对象初始化新对象时拷贝构造函数会被调用。拷贝构造函数的特点1.它是构造函数的一个重载必须通过引用传递接收同类型对象以防止编译器陷入无限递归允许存在额外参数但必须有默认值。2.在C中自定义类型进行值传递或值返回时均会自动调用该函数。3.若不进行显式调用编译器会自动生成默认版本。该版本对内置类型执行逐字节的浅拷贝对自定义类型的成员则会递归调用其自身的拷贝构造函数。4.当类直接管理外部资源如指针成员时默认生成的浅拷贝不满足需求需手动实现深拷贝若类成员全为内置类型或自定义类型的聚合如队列包含栈对象通常无需手动实现。此外若类已显式定义了析构函数来释放资源通常也必须手动实现拷贝构造以免重复释放内存。5.值返回会产生临时对象会触发拷贝传引用返回虽能减少拷贝但严禁返回已销毁的局部对象引用以防产生野引用。3. 析构函数析构函数在对象生命周期结束时自动调用用于释放对象占用的资源如动态内存、文件句柄、网络连接等。析构函数的名字是类名前加波浪号没有参数也没有返回值且一个类只能有一个析构函数。和构造函数相似的是内置类型不进行处理自定义类型会自动调用它自己的析构函数需要注意的是当一个类中并没有什么资源需要去释放时此时就使用编译器自己生成的析构函数就够用但是要是比如在类中向堆等需要自己手动来释放的资源一定要显式实现一个析构函数以避免内存泄漏。class Buffer { public: ~Buffer() { delete[] data; } private: char* data; };3.1 析构顺序对象的析构顺序与构造顺序相反先构造的后析构后构造的先析构。对于成员对象析构顺序与声明顺序相反对于继承体系先析构派生类再析构基类。class Base { public: ~Base() { std::cout Base 析构 std::endl; } }; class Derived : public Base { public: ~Derived() { std::cout Derived 析构 std::endl; } };4. 构造函数与析构函数的调用时机构造函数在对象创建时调用析构函数在对象销毁时调用。对象销毁的时机包括局部对象离开作用域、动态对象被 deletedelete关键字是C中后续用来申请空间new对应释放内存空间的关键字、程序结束时全局对象销毁等。void func() { Student s; // 构造 Student* p new Student(); // 构造 delete p; // 析构 } // s 在此处析构5.C中栈的实现#includeiostream using namespace std; typedef int STDataType; class Stack { public: Stack(int n 4) { a (STDataType*)malloc(sizeof(STDataType) * n); if (a nullptr) { perror(malloc failed!!!); return; } top 0; capacity n; } Stack(const Stack d) { a (STDataType*)malloc(sizeof(STDataType) * d.capacity); if (a nullptr) { perror(malloc failed!!!); return; } memcpy(this-a, d.a, sizeof(STDataType)*d.top); top d.top; capacity d.capacity; } void StackPush(STDataType x) { //考虑扩容条件 if (top capacity) { size_t newcapacity capacity * 2; STDataType* temp (STDataType*)realloc(a, sizeof(STDataType) * newcapacity); if (nullptr temp) { perror(realloc failed!!!); return; } a temp; capacity newcapacity; } a[top] x; } ~Stack() { free(a); a nullptr; top capacity 0; } void STPrint() { while (top) { cout a[--top] endl; } } private: STDataType* a; size_t top; size_t capacity; }; int main() { Stack s1; s1.StackPush(1); s1.StackPush(2); s1.STPrint(); return 0; }6. 总结构造函数和析构函数是 C 类设计的基石。构造函数负责对象的正确初始化析构函数负责资源的彻底释放。掌握默认构造、带参构造、拷贝构造、移动构造以及虚析构等关键概念并遵循资源管理的规范才能写出安全、高效的 C 代码。
阅读完成 · 觉得有帮助?