当前位置: 首页 > news >正文

C++修炼之构造函数与析构函数

默认成员函数上一章中我们谈到如果一个类中什么成员也没有那么这个类就叫作空类。其实这么说是不太严谨的因为一个类不可能什么都没有。当我们定义好一个类不做任何处理时编译器会自动生成以下6个默认成员函数默认成员函数如果用户没有手动实现则编译器会自动生成的成员函数构造函数主要完成初始化工作析构函数主要完成清理工作拷贝构造使用一个同类的对象初始化创建一个对象赋值重载把一个对象赋值给另一个对象取地址重载普通对象取地址操作取地址重载constconst对象取地址操作本章我们将学习两个默认成员函数——构造函数与析构函数。构造函数引例在C语言阶段我们实现栈的数据结构时有一件事很苦恼就是每当创建一个stack对象之前叫作定义一个stack类型的变量后首先得调用它的专属初始化函数StackInit来初始化对象。12345678910111213141516171819typedefintdataOfStackType;typedefstructstack{dataOfStackType* a;inttop;intcapacity;}stack;voidStackInit(stack* ps);//...intmain(){stack s;StackInit(s);//...return0;}这不免让人觉得有点麻烦。在C中构造函数为我们很好的解决了这一问题。构造函数的概念及特性构造函数是一个特殊的成员函数。构造函数虽然叫作构造但是其主要作用并不是开辟空间创建对象而是初始化对象。构造函数之所以特殊是因为相比于其它成员函数它具有如下特性函数名与类名相同无返回值对象实例化时编译器自动调用对应的构造函数构造函数可以重载举例12345678910111213141516171819202122232425classDate{public://无参的构造函数Date(){};//带参的构造函数Date(intyear,intmonth,intday){_year year;_month month;_day day;}private:int_year;int_month;int_day;};voidTestDate(){Date d1;//调用无参构造函数自动调用Date d2(2023, 3, 29);//调用带参构造函数自动调用}特别注意创建对象时编译器会自动调用构造函数若是调用无参构造函数则无需在对象后面使用()。否则会产生歧义编译器无法确定你是在声明函数还是在创建对象。错误示例12//错位示例Date d3();如果类中没有显式定义构造函数则C编译器会自动生成一个无参的默认构造函数一旦用户显式定义编译器将不再生成。12345678910111213141516classDate{public://若用户没有显示定义则编译器自动生成。/*Date(int year,int month,int day){_year year;_month month;_day day;}*/private:int_year;int_month;int_day;};默认生成构造函数对内置类型成员不作处理对自定义类型成员会调用它的默认构造函数C把类型分成内置类型基本类型和自定义类型。内置类型就是语言提供的数据类型如int、char、double…自定义类型就是我们使用class、struct、union等自己定义的类型。举例默认构造函数对内置类型12345678910111213141516171819202122classDate{public://此处不对构造函数做显示定义测试默认构造函数/*Date(){}*/voidprint(){cout _year - _month - _day endl;}private:int_year;int_month;int_day;};voidTestDate1(){Date d1;d1.print();}如图所示默认构造函数的确未对内置类型做处理。默认构造函数对自定义类型123456789101112131415161718192021222324252627282930classstack{public://此处对stack构造函数做显示定义stack(){cout stack() endl;_a nullptr;_top _capacity 0;}private:int* _a;int_top;int_capacity;};classqueue{public://此处不对queue构造函数做显示定义测试默认构造函数/*queue(){}*/private://自定义类型成员stack _s;};voidTestQueue(){queue q;}如图所示在创建queue对象时默认构造函数对自定义成员_s做了处理调用了它的默认构造函数stack()。这一波蜜汁操作让很多C使用者感到困惑与不满为什么要针对内置类型和自定义类型做不同的处理呢终于在C11中针对内置类型成员不初始化的缺陷又打了补丁即内置类型成员变量在类中声明时可以给默认值举例12345678910111213141516171819classDate{public://...voidprint(){cout _year - _month - _day endl;}private://使用默认值int_year 0;int_month 0;int_day 0;};voidTestDate2(){Date d2;d2.print();}默认值若不对成员变量做处理则使用默认值。无参的构造函数和全缺省的构造函数都称为默认构造函数并且默认构造函数只能有一个举例1234567891011121314151617181920212223242526classDate{public://无参的默认构造函数//Date()//{//}//全缺省的默认构造函数Date(intyear 0,intmonth 0,intday 0){_year year;_month month;_day day;}voidprint(){cout _year - _month - _day endl;}private:int_year 0;int_month 0;int_day 0;};析构函数析构函数与构造函数的特性相似但功能有恰好相反。构造函数是用来初始化对象的析构函数是用来销毁对象的。需要注意的是析构函数并不是对对象本身进行销毁因为局部对象出了作用域会自行销毁由编译器来完成而是在对象销毁时会自动调用析构函数对对象内部的资源做清理例如stack _s中的int* a。同样有了析构函数我们再也不用担心创建对象或定义变量后由于忘记释放内存而造成内存泄漏了。举例12345678910111213141516171819202122232425262728293031323334353637383940classStack{public:Stack(){//...}voidPush(intx){//...}boolEmpty(){// ...}intTop(){//...}voidDestory(){//...}private:// 成员变量int* _a;int_top;int_capacity;};voidTestStack(){Stack s;st.Push(1);st.Push(2);//过去需要手动释放st.Destroy();}析构函数的特性析构函数名是在类名前加上字符~无参数无返回值一个类只能有一个析构函数。若未显式定义系统会自动生成默认的析构函数析构函数不能重载举例123456789101112131415161718192021classDate{public:Date(){cout Date() endl;}~Date(){cout ~Date() endl;}private:int_year 0;int_month 0;int_day 0;};voidTestDate3(){Date d3;//d3生命周期结束时自动调用构造函数}为便于观察我们可以在析构函数内部写点儿东西。编译器生成的默认析构函数对自定类型成员调用它的析构函数举例12345678910111213141516171819202122232425262728293031323334353637classstack{public://此处对stack构造函数做显示定义stack(){cout stack() endl;_a nullptr;_top _capacity 0;}~stack(){cout ~Stack() endl;free(_a);_a nullptr;_top _capacity 0;}private:int* _a;int_top;int_capacity;};classqueue{public://此处不对queue构造函数做显示定义测试默认构造函数/*queue(){}*/private://自定义类型成员stack _s;};voidTestQueue1(){queue q;}这里可能有小伙伴会好奇为什么析构函数不像构造函数那样区分内置类型与自定义类型呢答案是因为内置类型压根不需要我们担心清理工作在其生命周期结束时会自动销毁。而自定义类型需要担心因为自定义类型里可能含有申请资源例如malloc申请内存须手动释放。
http://www.gsyq.cn/news/1359913.html

相关文章:

  • C++中多才多艺的 const
  • S-Video端口ESD防护方案解析:低电容TVS阵列选型与PCB布局实战
  • 【流体】二维稳态不可压缩层流通道流利用FVM和SIMPLE 解平行板间层流的速度、压力和温度【含Matlab源码 15558期】
  • 速度对决:2026实测几秒内搞定的PDF转Word闪电工具 - 时讯资讯
  • 写给新手的 asnumpy:昇腾原生 NumPy 到底是啥?
  • ISO 26262标准下嵌入式软件模型测试解决方案全解析
  • C语言不完全类型与抽象数据类型:从编译原理到模块化设计实战
  • NotebookLM显著性判断深度解析(Google Research未公开的置信度衰减模型)
  • 基于RT-Thread与硬件JPEG解码器的嵌入式音乐相册开发实践
  • AI智能体Skills设计:从API工具到核心能力的工程实践
  • 嵌入式开发硬件生态构建:MIPI屏、UVC摄像头与4G模块的选型与集成实战
  • 2026年探秘:直击geo源头厂家,揭秘背后的故事
  • 为合宙Air32开发板刷写USB DFU Bootloader的完整指南
  • LosslessCut 3.68.0 官方版下载(夸克网盘+百度网盘,SHA256校验)
  • 3分钟搞定!全平台资源下载神器res-downloader终极使用手册
  • 【行业首曝】AI Agent测试工具链选型红黑榜:LangTest vs Guardrails vs custom LLM-evaluator,附真实TPS/误报率/可解释性压测数据
  • AI知识管理工具采购决策树(2026版):基于217家企业的ROI建模,精准匹配团队规模/安全等级/知识密度
  • AI Agent如何重构私教服务流程:3个已被连锁健身房验证的降本增效模型
  • 3分钟上手跨平台资源下载神器:轻松获取微信视频号、抖音无水印内容
  • 救命!书匠策AI居然能让毕业论文“自己长出来“?一个教育博主的真实测评
  • 光伏板缺陷检测数据集|红外可见光双模态|无人机光伏巡检|智慧电网光伏识别数据集
  • 汽车12V电源防护:P6KE TVS二极管选型、设计与实战指南
  • 汽车12V电源保护:TVS二极管选型、应用与EMC测试实战
  • 基于RK3399核心板的智能PCR仪开发:从嵌入式系统到高精度温控
  • 5G FWA智能终端技术解析:从核心架构到运营商集采实战
  • 增程式电动汽车预测型能量管理策略【附算法】
  • 团队冲刺每日总结5.23
  • RK3588蓝牙功能完整测试指南:从驱动到应用实战
  • 全志T113-S3开发板XR829 WiFi蓝牙驱动加载、固件配置与稳定性测试全攻略
  • 全志T113-S3开发板WiFi与蓝牙功能实测:从驱动到应用的完整指南