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

【c++面向对象编程】第3篇:类与对象(二):构造函数与析构函数

目录一、一个让人头疼的问题二、构造函数对象出生时的“第一声啼哭”1. 最基本的构造函数2. 带参数的构造函数重载3. 初始化列表更高效的初始化方式三、默认构造函数那个“看不见”的函数四、析构函数对象临终前的“遗言”五、完整的例子动态字符串数组类六、三个容易踩的坑1. 构造函数里抛出异常2. 析构函数里再抛异常3. 忘记写析构函数导致内存泄露七、这一篇的收获一、一个让人头疼的问题继续用上一讲的Book类cppBook b; b.setPrice(128.5); // 必须记得手动初始化 b.print(); // 如果忘了setPriceprice是未定义的垃圾值C的结构体好歹可以用{0}初始化但C的类不行——因为类可能有复杂的内部逻辑简单的内存置零可能破坏状态。更麻烦的是如果你的类需要分配动态内存比如用new申请了一块空间用完必须手动delete。一旦忘记内存就泄露了。构造函数和析构函数就是用来解决这些问题的。二、构造函数对象出生时的“第一声啼哭”构造函数是一种特殊的成员函数名字和类名完全相同没有返回值连void都不写在创建对象时自动调用可以重载多个构造函数参数不同1. 最基本的构造函数cppclass Book { private: string title; string author; double price; public: // 构造函数——名字和类一样没返回值 Book() { title 未知; author 未知; price 0.0; cout 构造函数被调用了 endl; } void print() { cout title , author , price endl; } }; int main() { Book b; // 自动调用构造函数输出构造函数被调用了 b.print(); // 输出未知, 未知, 0 }注意最后一行的Book b;——我们没有写任何“初始化”的代码但对象已经有了合理的默认值。2. 带参数的构造函数重载一个类可以有多个构造函数只要参数不同cppclass Book { private: string title; string author; double price; public: // 默认构造函数 Book() { title 未知; author 未知; price 0.0; } // 带三个参数的构造函数 Book(string t, string a, double p) { title t; author a; price p; } // 只传书名的构造函数 Book(string t) { title t; author 佚名; price 0.0; } void print() { cout 《 title 》 author ¥ price endl; } }; int main() { Book b1; // 调用默认构造函数 Book b2(C Primer, Lippman, 128.5); // 调用3参数构造 Book b3(三体); // 调用1参数构造 b1.print(); // 《未知》 未知 ¥0 b2.print(); // 《C Primer》 Lippman ¥128.5 b3.print(); // 《三体》 佚名 ¥0 }3. 初始化列表更高效的初始化方式上面的构造函数在函数体里赋值但还有更正统的写法——初始化列表cppBook(string t, string a, double p) : title(t), author(a), price(p) { // 函数体可以为空或者写其他逻辑 }:后面的title(t)意思是“用参数t来初始化title成员变量”。为什么要用初始化列表对于string、vector等有构造函数的类型初始化列表直接构造一次在函数体里赋值会先默认构造再赋值多一步开销const成员变量和引用类型必须用初始化列表成员变量的初始化顺序按它们在类中声明的顺序不是按初始化列表的顺序cppclass Demo { private: const int id; // const成员必须用初始化列表 int ref; // 引用必须用初始化列表 string name; public: Demo(int i, int r, string n) : id(i), ref(r), name(n) { // 这里id和ref已经初始化好了 } };三、默认构造函数那个“看不见”的函数如果你写一个类没有定义任何构造函数编译器会悄悄给你生成一个默认构造函数什么也不做。cppclass Simple { int x; string s; // 编译器会生成一个 Simple() {} }; Simple obj; // 可以编译但x是垃圾值s是空字符串但有一个陷阱一旦你自己写了任何一个构造函数编译器就不再生成默认构造函数。cppclass Book { public: Book(string t) { title t; } // 写了构造函数 private: string title; }; Book b1(C); // ✅ 没问题 Book b2; // ❌ 编译错误没有默认构造函数如果你既想要自己的构造函数又想要无参的版本必须显式写出来cppBook() {} // 或者 default (C11)C11提供了更简洁的写法cppBook() default; // 让编译器生成默认版本四、析构函数对象临终前的“遗言”析构函数是构造函数的“镜像”名字是~类名没有参数不能重载一个类只有一个析构函数没有返回值对象销毁时自动调用cppclass Book { private: string* pComment; // 指向动态分配的评论 public: Book(string comment) { pComment new string(comment); cout 构造分配内存 endl; } ~Book() { delete pComment; // 释放内存 cout 析构释放内存 endl; } }; int main() { Book b(很好看的一本书); // 函数结束时b被销毁析构函数自动调用 } // 输出 // 构造分配内存 // 析构释放内存什么时候调用析构函数对象类型析构时机局部对象栈上离开作用域时如函数结束静态局部对象程序结束时全局对象程序结束时new创建的对象显式调用delete时五、完整的例子动态字符串数组类把构造和析构结合起来写一个管理动态数组的类StringArraycpp#include iostream #include string using namespace std; class StringArray { private: string* data; // 指向动态数组的指针 int size; // 数组大小 public: // 构造函数分配内存并初始化 StringArray(int n) : size(n) { data new string[n]; cout 分配了 n 个字符串的空间 endl; } // 析构函数释放内存 ~StringArray() { delete[] data; cout 释放了 size 个字符串的空间 endl; } // 设置元素 void set(int index, const string s) { if (index 0 index size) { data[index] s; } } // 获取元素 string get(int index) { if (index 0 index size) { return data[index]; } return ; } // 打印所有 void print() { for (int i 0; i size; i) { cout [ i ] data[i] endl; } } }; int main() { StringArray arr(3); // 构造分配内存 arr.set(0, Hello); arr.set(1, World); arr.set(2, C); arr.print(); // 函数结束arr被销毁 → 析构函数自动调用释放内存 return 0; }运行结果text分配了3个字符串的空间 [0] Hello [1] World [2] C 释放了3个字符串的空间注意我们没有手动调用任何“释放”函数析构函数自动帮我们做了。六、三个容易踩的坑1. 构造函数里抛出异常如果在构造函数里抛异常对象被认为“没有构造完成”析构函数不会被调用。这意味着构造函数里已经分配的资源需要自己处理。cppBook() { p new int[100]; throw error; // 如果这里抛异常~Book()不会被调用内存泄露 }解决方案用智能指针后面的章节会讲或者在构造函数里用try-catch。2. 析构函数里再抛异常极其危险如果析构函数在栈展开期间处理另一个异常时又抛出异常程序会直接调用terminate()崩溃。cpp~Book() { delete p; throw 析构异常; // ❌ 千万别这么写 }规则析构函数应该吞掉所有异常只做清理不抛出任何东西。3. 忘记写析构函数导致内存泄露如果你的类里有指针成员并且你在构造函数里用new分配了内存必须写析构函数用delete释放否则内存就泄露了。cppclass Leaky { int* p; public: Leaky() { p new int[1000]; } // 没有析构函数 → 内存泄露 };七、这一篇的收获你现在应该理解构造函数在对象创建时自动调用适合做初始化析构函数在对象销毁时自动调用适合做清理构造函数可以重载多个版本初始化的优先级初始化列表 构造函数体内的赋值如果你管理了动态资源new必须提供析构函数去释放 小作业写一个IntArray类构造函数接收大小n并分配n个int的空间析构函数释放空间。提供set()和get()方法。在main中创建对象观察构造和析构的调用时机。下一篇预告第4篇《类与对象三拷贝构造函数与深浅拷贝问题》——当你把一个对象赋值给另一个对象时背后发生了什么默认的拷贝行为为什么可能导致程序崩溃

相关文章:

【c++面向对象编程】第3篇:类与对象(二):构造函数与析构函数

目录 一、一个让人头疼的问题 二、构造函数:对象出生时的“第一声啼哭” 1. 最基本的构造函数 2. 带参数的构造函数(重载) 3. 初始化列表:更高效的初始化方式 三、默认构造函数:那个“看不见”的函数 四、析构函…...

Letta框架:全栈AI应用开发,从模型集成到部署上线的完整解决方案

1. 项目概述:一个开箱即用的AI应用开发框架最近在折腾AI应用开发的朋友,估计都绕不开一个核心痛点:想法很美好,落地很骨感。从模型调用、提示词工程,到前后端集成、状态管理,再到部署上线,每个环…...

【c++面向对象编程】第2篇:类与对象(一):定义第一个类——成员变量与成员函数

目录 一、从一个日常需求开始 二、定义你的第一个类 三、访问修饰符:public、private、protected 举个例子,看看区别: 四、成员变量怎么声明? 五、成员函数:两种实现方式 方式一:类内实现&#xff08…...

AI编程智能体评估平台CodingAgentExplorer:从原理到实践的系统评测指南

1. 项目概述:一个探索智能体编码能力的开源工具最近在GitHub上闲逛,发现了一个挺有意思的项目:tndata/CodingAgentExplorer。光看名字,你可能会觉得这又是一个“AI写代码”的工具,市面上这类工具已经多如牛毛了。但当我…...

iPhone 5c中国遇冷复盘:产品定价、市场预期与战略博弈的深度解析

1. 项目概述:一次关于市场预期的“误判”复盘2013年秋天,苹果公司发布了被外界普遍视为“专为新兴市场打造”的iPhone 5c。这款拥有多彩聚碳酸酯外壳的手机,在发布前就被贴上了“廉价iPhone”的标签,尤其是针对像中国这样庞大且正…...

《Java面试85题图解版(二)》进阶深化中篇:Spring核心 + 数据库进阶

📘 《Java面试85题图解版(二)》进阶深化中篇:Spring核心 数据库进阶 阅读提示:这是“图解比喻一句话总结”面试题库第二篇的进阶深化中篇,覆盖Spring核心与Spring Boot(9题)和数据库…...

物联网标准演进与云平台破局:从M2M到IoT的实战路径

1. 从M2M到IoT:一场迟来的标准革命十多年前,当我第一次接触“机器对机器”这个概念时,感觉它就像个被锁在工厂车间里的幽灵——功能强大,但离普通人的生活无比遥远。那时的M2M,谈论的是专用网络、私有协议和封闭的垂直…...

EDA工程师成长与验证技术演进:从算法到芯片的实践闭环

1. 从算法到芯片:一位EDA工程师的成长路径解析在半导体这个行当里待久了,你会发现,那些真正能把工具做“透”、把流程理“顺”的人,往往自己就亲手“焊”过板子、调过RTL、追过时序违例。Prakash Narain的故事,就是一个…...

ClawMorph:为OpenClaw AI智能体实现安全可逆的“一键换装”

1. 项目概述:一个为AI智能体“一键换装”的开发者工具如果你正在使用OpenClaw这类AI智能体框架,并且厌倦了每次想让智能体扮演不同角色(比如从产品经理切换到设计师)时,都需要手动去修改一堆配置文件、提示词文件&…...

番茄小说下载器:打造个人专属离线小说图书馆的完整指南

番茄小说下载器:打造个人专属离线小说图书馆的完整指南 【免费下载链接】fanqienovel-downloader 下载番茄小说 项目地址: https://gitcode.com/gh_mirrors/fa/fanqienovel-downloader 你是否曾在通勤路上突然想读小说,却因为网络信号不佳而无法加…...

从CEO到营销技术专家:创业者退休后的身份重构与价值延续

1. 从创业者到“退休者”:身份的骤然转变卖掉自己一手创办并经营了近四十年的公司,这种感觉,远非“退休”二字可以概括。它不是一次计划已久的悠闲旅行,更像是一场毫无预兆的急刹车。前一天,你还在会议室里为下一代产品…...

DevSquad:基于Docker Compose的一站式开发环境解决方案

1. 项目概述:一个为开发者量身定制的“特种作战小队”如果你是一名开发者,无论是独立作战还是身处团队,一定都经历过这样的场景:为了搭建一个项目,你需要反复安装和配置各种开发工具、运行环境、依赖包。从代码编辑器、…...

AI心智理论评估:VLM意图理解接近人类,但视角采样能力存在瓶颈

1. 项目概述:当AI“读懂”人心时,它在想什么?在人工智能领域,有一个听起来颇具哲学意味的挑战:如何让机器理解“心智”?这不仅仅是让AI识别图像中的物体或生成流畅的文本,而是让它能够像人类一样…...

5分钟快速上手:Blender 3MF插件让你轻松实现3D打印模型转换

5分钟快速上手:Blender 3MF插件让你轻松实现3D打印模型转换 【免费下载链接】Blender3mfFormat Blender add-on to import/export 3MF files 项目地址: https://gitcode.com/gh_mirrors/bl/Blender3mfFormat 你是否曾经在Blender中精心设计了色彩丰富的3D模型…...

2012年Accellera标准演进:SystemC、UCIS与AMS如何重塑EDA设计流程

1. 回顾2012:Accellera在电子设计自动化标准演进中的关键一年对于从事半导体设计,特别是系统级设计、验证和IP集成的工程师来说,2012年是一个值得标记的年份。那一年,行业正从2008年金融危机后的缓慢复苏中走出,移动计…...

联发科2012年崛起:从功能机到智能机的转型与挑战

1. 从功能机到智能机的惊险一跃:联发科的2012年2012年,对于全球移动芯片行业来说,是几家欢喜几家愁的一年。诺基亚和黑莓的持续衰落,直接拖垮了像ST-Ericsson这样深度绑定的芯片供应商;即便是巨头如高通,也…...

西安石油大学仪光实践协会4月活动机械蝴蝶台灯

项目简介该项目使用stm32芯片设计了一个灯光,300减速,可灯光颜色变化,和电机转向控制。制作了一个简单有趣的动态可控台灯。使用电源控制ic芯片,可与连接电池,对电池进行充电,并且显示电池剩余电量。实现制…...

AMD Ryzen终极性能调优秘籍:5个高效调试技巧让你完全掌控处理器性能

AMD Ryzen终极性能调优秘籍:5个高效调试技巧让你完全掌控处理器性能 【免费下载链接】SMUDebugTool A dedicated tool to help write/read various parameters of Ryzen-based systems, such as manual overclock, SMU, PCI, CPUID, MSR and Power Table. 项目地址…...

从零部署私有化AI对话框架:igogpt架构解析与实战指南

1. 项目概述与核心价值最近在折腾AI应用部署的朋友,可能都听说过一个词叫“套壳ChatGPT”。这类项目通常是把OpenAI的API接口包装一下,做个Web界面,让用户能更方便地使用。但今天要聊的这个项目——igolaizola/igogpt,它给我的感觉…...

从AMD Ryzen数据误读看硬件市场分析:如何辨别数据信号与噪声

1. 从一则旧闻谈起:数据解读的陷阱与行业洞察2017年7月,一则关于AMD Ryzen处理器市场份额的新闻在科技圈引发了不小的讨论。当时,多家媒体援引第三方基准测试软件Passmark的数据,宣称AMD凭借新发布的Ryzen架构,正在从英…...

Obsidian Quiz Generator:用AI从笔记生成交互测验,打造学习闭环

1. 项目概述:用AI将笔记变成互动测验 如果你和我一样,是个重度Obsidian用户,同时又经常需要备考、复习或者制作教学材料,那你肯定体会过那种痛苦:面对几十上百页的笔记,想要生成一些高质量的练习题来检验学…...

TTS听觉校对法:技术写作质量提升的工程实践指南

1. 为什么我们需要“听”自己的文字:一个被忽视的校对革命作为一名写了十几年技术文档和博客的老兵,我敢说,最让我头疼的不是构思,也不是码字,而是最后那一步——校对。你肯定也经历过:一封精心撰写的邮件发…...

ATE PCB组装:半导体测试中的精密工艺与挑战解析

1. ATE PCB组装:半导体测试的基石与挑战 在半导体行业,一颗芯片从设计到最终封装出厂,其性能与可靠性的验证是决定产品成败的最后一环。随着芯片工艺节点不断微缩,集成度呈指数级增长,对测试环节的要求也达到了前所未有…...

无线充电技术:从手机标配到多场景应用的挑战与机遇

1. 无线充电市场现状:繁荣表象下的应用困境手机无线充电,现在几乎成了旗舰机的标配。从咖啡馆、机场到汽车中控台,充电垫的身影随处可见。作为一名在电源管理和消费电子领域摸爬滚打了十几年的工程师,我亲眼见证了Qi标准从实验室走…...

Blender 3MF插件:5分钟掌握3D打印文件格式转换的完整方案

Blender 3MF插件:5分钟掌握3D打印文件格式转换的完整方案 【免费下载链接】Blender3mfFormat Blender add-on to import/export 3MF files 项目地址: https://gitcode.com/gh_mirrors/bl/Blender3mfFormat 你是否曾经在Blender中精心设计了完美的3D模型&…...

从1991年Wescon展会看测试测量技术演进:DSP、GPIB与经典仪器解析

1. 从一份老杂志的周五测验说起:重温1991年Wescon展会的测试测量世界最近在整理资料时,翻到一篇2016年《EE Times》上的老文章,标题叫“周五测验:Wescon测试产品”。文章的核心是带读者回顾1991年EDN杂志为Wescon展会出版的一份厚…...

从专利数量到创新质量:解读中国专利申请背后的产业逻辑与价值评估

1. 从“专利数量”到“创新质量”:一个从业者的深度观察最近和几位在半导体和物联网领域做研发的朋友聊天,话题不约而同地转到了知识产权上。大家普遍的感觉是,现在无论是产品立项、技术合作还是出海竞争,专利已经从一个“锦上添花…...

【领域驱动设计 开篇】零 来源及学习路径

DDD是什么 2003 年,Eric Evans 写了《领域驱动设计:软件核心复杂性应对之道》一书,正式提出了这种方法。领域驱动设计的英文是 Domain-Driven Design,简称 DDD。 按照作者自己的说法,“DDD 是一种开发复杂软件的方法”…...

芯片设计中的工程迷信与理性实践:从经验法则到数据驱动

1. 项目概述:从“黑色星期五”迷信到工程设计的理性思考作为一名在电子设计自动化(EDA)和半导体行业摸爬滚打了十几年的工程师,我每天打交道的是精确到纳秒的时序分析、纳米级的物理规则和数以亿计的晶体管布局。在这个世界里&…...

虚拟原型技术:软硬件协同开发与多核处理器调试新范式

1. 虚拟原型平台:从芯片设计到软件集成的范式转变在嵌入式系统开发领域,尤其是涉及复杂多核处理器的项目里,一个长期存在的“鸡生蛋还是蛋生鸡”的困境一直困扰着工程师们:硬件原型板(EVB)尚未就绪&#xf…...