资讯动态

【C++】类的六个默认成员函数:构造、析构、拷贝构造和赋值重载介绍

发布时间:2026/10/16 21:26:32 来源:尧图企业网站定制
引言在 C 中如果我们不手动实现类中的部分成员函数编译器会自动生成 6 个默认成员函数。其中最核心、面试最高频的就是构造函数、析构函数、拷贝构造函数、赋值运算符重载本文结合原理与坑点逐一讲解。一、构造函数构造函数的核心作用对象初始化。对象在实例化创建的时候系统会自动调用构造函数给对象成员赋初始值。1.1.构造函数的特点函数名和类名完全相同。没有返回值不写返回类型也不用写void。对象创建实例化时编译器自动调用不需要手动调用。支持函数重载可以写多个构造函数。若我们没有显式写任何构造函数编译器会自动生成无参默认构造函数一旦自己写了构造函数编译器就不再生成默认构造。默认构造无参构造、全缺省构造统称为默认构造一个类只能有一个默认构造同时写会产生调用歧义。注编译器自动生成的默认构造对内置类型成员不做初始化对自定义类型成员会调用它自己的构造函数完成初始化。class Date { public: // 全缺省构造默认构造 Date(int year 2026, int month 1, int day 1) { _year year; _month month; _day day; } private: int _year; int _month; int _day; };二、析构函数析构函数和构造函数功能相反负责对象资源清理对象生命周期结束时编译器自动调用。2.1.析构函数的特点名字~ 类名。无参数、无返回值。一个类只能有 1 个析构函数不能重载。没有手写析构编译器自动生成默认析构。对象销毁时自动调用。默认析构对内置类型成员不处理对自定义类型成员自动调用它的析构函数。重点如果类内申请了堆内存资源比如 Stack 动态数组必须手写析构释放资源否则内存泄漏没有申请资源直接用默认析构即可。局部对象后定义的对象先析构。class Stack { public: Stack(int cap 4) { _a new int[cap]; _top 0; _capacity cap; } // 析构释放堆上数组 ~Stack() { delete[] _a; _a nullptr; _top _capacity 0; } private: int* _a; int _top; int _capacity; };三、构造函数和析构函数的区别构造函数析构函数核心作用对象初始化创建对象申请资源对象清理销毁释放对象占用的资源函数名称与类名完全相同~ 类名波浪号作为标识参数可以无参也可以带参数支持重载无参数不支持重载一个类仅有一个析构调用时机对象创建 / 实例化时自动调用对象生命周期结束销毁时自动调用调用顺序局部对象先定义先构造局部对象后定义先析构和构造顺序相反编译器默认生成没有手写任何构造编译器生成默认构造一旦手写构造不再生成无论有没有写其他函数不手写析构就会生成默认析构自定义类型成员处理自动调用成员的构造函数自动调用成员的析构函数总而言之就是构造是对象出生时做的准备工作析构是对象死亡时做的收尾清理工作二者成对出现四、拷贝构造函数拷贝构造是特殊的构造函数用一个已经存在的同类型对象去初始化新建对象。class Date { public: // 拷贝构造函数声明第一个参数必须是同类引用其他参数要有缺省值 Date(const Date d); private: int _year; int _month; int _day; }; // 定义 Date::Date(const Date d) { _year d._year; _month d._month; _day d._day; }注如果使用传值传参会再次调用拷贝构造无限递归直接编译报错。4.1拷贝构造函数特点属于构造函数的重载。第一个参数必须是同类对象的引用其余参数必须带缺省值。不手写拷贝构造编译器会自动生成默认拷贝构造内置类型按字节直接拷贝浅拷贝自定义类型成员调用该类型的拷贝构造调用场景使用旧对象初始化新对象Date d2(d1);/Date d2 d1;函数传值传参形参是类对象函数传值返回返回类对象会产生临时对象调用拷贝构造五、浅拷贝和深拷贝5.1浅拷贝单纯按内存字节拷贝直接拷贝成员变量的值。 如果成员是指针只会拷贝指针变量本身的值也就是堆内存地址两个对象的指针指向同一块堆空间。适用场景像 Date 类成员都是普通内置变量没有堆资源浅拷贝完全够用。class Date { public: Date(int year 2026, int month 1, int day 1) { _year year; _month month; _day day; } private: int _year; int _month; int _day; }; int main() { Date d1(2026, 10, 14); Date d2 d1; // 调用编译器默认拷贝构造浅拷贝直接拷贝三个int的值 return 0; }注意Stack 这种动态内存类。两个对象共用同一块堆数组析构的时候会对同一块内存释放两次程序则会直接崩溃。class Stack { public: Stack(int cap 4) { _a new int[cap]; // 在堆上申请内存 _top 0; _capacity cap; } ~Stack() { delete[] _a; // 析构释放堆内存 _a nullptr; } private: int* _a; int _top; int _capacity; }; int main() { Stack st1; Stack st2 st1; // 默认浅拷贝只拷贝 _a、_top、_capacity 的值 // st1._a 和 st2._a 保存同一个堆地址 return 0; // 函数结束先析构st2delete[] 释放这块堆内存 // 再析构st1再次 delete[] 释放**已经释放过的同一块内存** // 重复释放内存程序则会直接崩溃 }5.2深拷贝不直接复制指针地址重新开辟一块独立的堆内存再把源对象的数据拷贝过去两个对象拥有各自独立资源。例如Stack::Stack(const Stack st) { // 1. 新开一块内存大小和源对象一致 _a new int[st._capacity]; // 2. 拷贝数据 memcpy(_a, st._a, sizeof(int)*st._top); _top st._top; _capacity st._capacity; }深拷贝之后两个对象的_a指向不同堆空间析构各自释放自己内存不会重复释放。六、拷贝构造函数和赋值运算符重载的区别拷贝构造创建新对象用已有对象初始化它。Stack s2 s1;s2 是刚刚新建的。赋值运算符重载两个都已经存在的对象把一个对象的数据赋值给另一个。s2 s1;s1、s2 都已经创建完成。6.1赋值运算符重载介绍赋值重载也是默认成员函数不手写编译器也会生成默认版本同样是浅拷贝。 声明格式返回值类型operator(参数)Stack Stack::operator(const Stack st) { // 防止自己给自己赋值 if(this ! st) { // 释放当前对象旧空间 delete[] _a; // 开辟新空间 拷贝数据深拷贝 _a new int[st._capacity]; memcpy(_a, st._a, sizeof(int)*st._top); _top st._top; _capacity st._capacity; } return *this; }拷贝构造赋值运算符重载对象状态新对象正在创建还没初始化两个对象都已经存在触发写法Stack s2(s1);Stack s2 s1;s2 s1;核心工作初始化新对象覆盖已有对象的成员资源处理有堆内存深拷贝开辟新空间深拷贝先释放旧空间再开辟新空间七、总结构造创建对象初始化析构销毁对象清理资源。成对使用。拷贝构造新建对象的拷贝必须引用传参区分深浅拷贝。赋值重载已有对象之间赋值要处理自赋值、释放旧资源。准则只要类中动态申请堆内存必须手动写 3 个函数析构函数 拷贝构造深拷贝 赋值重载深拷贝没有堆资源编译器默认生成的就足够使用。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑