C++真正的入门:类和对象中
文章目录前言本篇文章是对类和对象的补充想了解类和对象前面内容的可以看看这篇博客 [https://blog.csdn.net/xsc_74759805/article/details/162817432?spm1011.2415.3001.10575sharefrommp_manage_link](https://blog.csdn.net/xsc_74759805/article/details/162817432?spm1011.2415.3001.10575sharefrommp_manage_link)。一、类的默认成员函数续1.运算符重载特点常见问题补充2.赋值运算符重载特点与拷贝构造的区别3. 取地址运算符重载const成员函数取地址运算符重载二、初始化列表1.定义2.特点3.总结4.补充前言本篇文章是对类和对象的补充想了解类和对象前面内容的可以看看这篇博客https://blog.csdn.net/xsc_74759805/article/details/162817432?spm1011.2415.3001.10575sharefrommp_manage_link。一、类的默认成员函数续1.运算符重载特点当运算符作用于类类型对象时C 允许通过运算符重载为运算符赋予新语义。C 规定类对象使用运算符时会自动转换为调用对应重载函数若无匹配的重载函数代码编译报错。运算符重载本质是命名特殊的函数函数名由operator关键字 需要重载的运算符组合而成。和普通函数一致拥有返回值、参数列表与函数体。重载运算符的参数数量和该运算符原本操作数数量相等一元运算符对应 1 个参数二元运算符对应 2 个参数二元运算符左侧操作数传给第一个参数右侧操作数传给第二个参数。// 负号 -a唯一操作数a传给唯一参数//全局Personoperator-(constPersonp){returnPerson(-p.age);}// 使用Person b -a;// 操作数a → 第一个唯一参数 p//成员Person Person::operator-(){returnPerson(-this-age);}// 使用Person b -a;// 隐含this a占用唯一操作数无需显式参数注意上述内容只适用于全局重载运算符所有操作数全部显式作为函数参数参数个数严格等于运算符操作数当你写成员函数重载时由于this指针的隐藏会少一个参数若将运算符重载实现为类成员函数第一个操作数会隐式绑定this指针因此成员形式的运算符重载参数个数比操作数数量少一个。运算符重载不会改变原有运算符的优先级与结合性和内置类型运算符规则保持相同。以下 5 个运算符禁止重载.*、::、sizeof、?:、.选择题高频考点需要熟记。重载运算符的参数中至少要有一个类 / 自定义类型参数不能修改内置类型运算符逻辑例如不允许写int operator(int x, int y)。原因如果允许全部是内置类型编译器无法区分是调用你写的重载函数还是语言原生内置运算。例若允许 int operator(int a, int b)编译器遇到 12 时分不清该用原生加法还是你的自定义函数产生二义性。彻底破坏 C 基础语法一致性。合法示例// 自定义类classPoint{intx,y;};// 全局重载至少一个Point自定义类型Pointoperator(Point a,Point b){return{a.xb.x,a.yb.y};}// 成员重载自带thisPoint*天然满足条件Pointoperator(Point b){return{this-xb.x,this-yb.y};}类不需要重载全部运算符仅重载对当前类有实际意义的运算符即可。例如Date类重载operator-有业务含义但重载operator无实际作用。自增运算符分前置a与后置a二者重载函数名均为operator无法直接区分。C 规定后置重载时额外增加一个int形参以此和前置形成函数重载完成区分。Dateoperator(){cout前置endl;//...return*this;}Dateoperator(int){Date tmp;cout后置endl;//....returntmp;}intmain(){Dated1(2024,7,5);Dated2(2024,7,6);// 编译器会转换成d1.operator();d1;// 编译器会转换成d1.operator(0);d1;return0;}流运算符、必须重载为全局函数如果写成成员函数this会占据第一个参数运算符左操作数调用语法会变成对象cout不符合阅读与使用习惯。实现为全局函数时将ostream/istream流对象放在第一个参数自定义类对象作为第二个参数就能支持常规cout 对象写法。// 错误示范成员函数重载classTest{public:ostreamoperator(ostreamos){os数据;returnos;}};intmain(){Test t;tcout;// 只能这么写极度反人类// cout t; 直接编译报错return0;}#includeiostreamusingnamespacestd;classPerson{private:string name;intage;public:Person(string n,inta):name(n),age(a){}// 声明全局流运算符为友元访问私有成员friendostreamoperator(ostreamos,constPersonp);friendistreamoperator(istreamis,Personp);};// 输出流 全局重载ostreamoperator(ostreamos,constPersonp){os姓名p.name年龄p.age;returnos;// 返回流引用支持链式调用 cout a b;}// 输入流 全局重载对象不能const要修改成员istreamoperator(istreamis,Personp){isp.namep.age;returnis;}intmain(){Personp(张三,20);coutpendl;// 编译器翻译成operator(cout, p);Personp2(,0);cinp2;coutp2;return0;}不能通过连接语法中没有的符号来创建新的操作符比如operator。常见问题重载为全局的面临对象访问私有成员变量的问题方法 1把私有成员改成 public 公有方法 2类提供 getXXX 读取接口#includeiostreamusingnamespacestd;classDate{private:intyear,month,day;// 私有不变public:Date(inty2026,intm1,intd1):year(y),month(m),day(d){}// getter接口intgetYear()const{returnyear;}intgetMonth()const{returnmonth;}intgetDay()const{returnday;}};// 全局运算符重载通过getter间接访问私有Dateoperator(constDated,intn){returnDate(d.getYear(),d.getMonth(),d.getDay()n);}intmain(){Dated(2026,7,14);Date resd10;coutres.getYear()-res.getMonth()-res.getDay();return0;}方法 3将全局重载函数声明为类的友元函数 friend方法 4不使用全局函数把运算符重载为类的成员函数调用运算符重载我们在使用运算符重载时其实是在调用函数。booloperator(Dateconsta1,Dateconsta2){returna1._daya2._daya1._montha2._montha1._yeara2._year;}intmain(){Dated1(2024,7,5);Dated2(2024,7,6);// 运算符重载函数可以显示调用operator(d1,d2);// 编译器会转换成operator(d1, d2);d1d2;return0;写成成员函数则为booloperator(constDateother)const{returnyother.ymother.mdother.d;}intmain(){Dated1(2026,7,14);Dated2(2026,7,14);Dated3(2026,8,1);// 隐式调用编译器自动转换boolret1d1d2;cout隐式调用 d1 d2ret1endl;// 显式调用直接调用成员函数 operatorboolret2d1.operator(d2);cout显式调用 d1.operator(d2)ret2endl;}注意这里的d1传的是左边隐藏的this指针而d2则是代表右边other。补充typedefvoid(A::*PF)();//成员函数指针类型intmain(){// C规定成员函数要加才能取到函数指针PF pfA::func; A obj;//定义A类对象tmp// 对象调⽤成员函数指针时使⽤.*运算符(obj.*pf)();return0;}2.赋值运算符重载赋值运算符重载是一个默认成员函数用于完成两个已经存在的对象之间的拷贝赋值这里要注意跟拷贝构造区分拷贝构造用于一个对象拷贝初始化给另一个要创建的对象。特点赋值运算符重载是一个运算符重载规定必须重载为成员函数。赋值运算重载的参数建议写成 const 当前类类型引用否则会传值传参会有拷贝。原因赋值运算符左侧必须是当前类对象编译器要求operator左操作数作为调用者this指针全局函数无法隐式持有this因此标准强制operator只能是成员函数。对比、-、、可全局友元、()、[]、-只能成员。classPerson{private:string name;public:// 构造Person(string nunknown):name(n){cout构造函数nameendl;}// 拷贝构造函数观察拷贝触发Person(constPersonp){namep.name;cout拷贝构造触发复制nameendl;}// 方式1错误示范参数为值传递 Person pPersonoperator(Person p){this-namep.name;return*this;}// 方式2标准推荐 const Person pPersonoperator(constPersonp){this-namep.name;return*this;}};intmain(){Persona(张三);Personb(李四);ab;// 赋值调用return0;}如果使用传值传递实参b传给形参Person p值传递自动调用拷贝构造函数复制一份临时对象p消耗更多的内存。有返回值且建议写成当前类类型引用引用返回可以提高效率有返回值目的是为了支持连续赋值场景。原因如果写成void类型则无法进行连续赋值。不支持连续赋值 a b c。同时因为自动调用拷贝构造函数效率低下。没有显式实现时编译器会自动生成一个默认赋值运算符重载默认赋值运算符重载行为跟默认拷贝构造函数类似对内置类型成员变量会完成值拷贝 / 浅拷贝一个字节一个字节的拷贝对自定义类型成员变量会调用它的赋值重载函数。像 Date 这样的类成员变量全是内置类型且没有指向什么资源编译器自动生成的赋值运算符重载就可以完成需要的拷贝所以不需要我们显式实现赋值运算符重载。像 Stack 这样的类虽然也都是内置类型但是_a 指向了资源编译器自动生成的赋值运算符重载完成的值拷贝 / 浅拷贝不符合我们的需求所以需要我们自己实现深拷贝对指向的资源也进行拷贝。像 MyQueue 这样的类型内部主要是自定义类型 Stack 成员编译器自动生成的赋值运算符重载会调用 Stack 的赋值运算符重载也不需要我们显式实现 MyQueue 的赋值运算符重载。这里还有一个小技巧如果一个类显式实现了析构并释放资源那么它就需要显式写赋值运算符重载否则就不需要。与拷贝构造的区别赋值重载完成两个已经存在的对象之间的拷贝赋值而拷贝构造函数用于一个对象拷贝初始化给另一个要创建的对象。同时为什么赋值重载返回值是*this因为虽然对象的内容改变但还是原来的对象。3. 取地址运算符重载const成员函数将 const 修饰的成员函数称之为 const 成员函数const 修饰成员函数放到成员函数参数列表的后面。const 实际修饰该成员函数隐含的 this 指针表明在该成员函数中不能对类的任何成员进行修改。例如const 修饰 Date 类的 Print 成员函数后Print 隐含的 this 指针原本为 Date* const this会被修饰为 const Date* const this。usingnamespacestd;classDate{public:Date(intyear1,intmonth1,intday1){_yearyear;_monthmonth;_dayday;}// void Print(const Date* const this) constvoidPrint()const{cout_year-_month-_dayendl;}private:int_year;int_month;int_day;};取地址运算符重载取地址运算符重载分为普通取地址运算符重载和const取地址运算符重载一般这两个函数编译器自动生成的就足够我们使用不需要显示调用。除非是一些很特殊的场景比如我们不想让别人获取到当前类对象的地址就可以自己手动实现一份随意返回一个地址。classDate{public:Date*operator(){returnthis;// return nullptr;}constDate*operator()const{returnthis;// return nullptr;}private:int_year;// 年int_month;// ⽉int_day;// ⽇};二、初始化列表1.定义之前我们实现构造函数时初始化成员变量主要使用函数体内赋值构造函数初始化还有一种方式就是初始化列表初始化列表的使用方式是以一个冒号开始接着是一个以逗号分隔的数据成员列表每个 “成员变量” 后面跟一个放在括号中的初始值或表达式。示例classPerson{private:intage;public:Person(inta):age(a){cout构造endl;}};初始化列表本质C 类的成员变量本质是在进入构造函数函数体之前就完成内存分配与初始化。初始化列表就是给成员变量提供初始值的唯一初始化阶段相当于成员变量的定义初始化位置。构造函数大括号 {} 内部只是赋值操作不是初始化。初始化列表和函数体内赋值的关键区别在于前者是对成员变量的初始化是第一次赋值而后者初始化已经完成是对前者的值进行覆盖。2.特点每个成员变量在初始化列表中只能出现一次语法理解上初始化列表可以认为是每个成员变量定义初始化的地方。原因初始化列表对应成员变量创建时的初始化阶段每个成员一生只会初始化一次因此语法禁止在初始化列表重复书写同一成员而构造函数内部是赋值阶段不受此限制。classPerson{private:int_age;public:Person(inta):_age(a){_agea;cout构造endl;}};这是允许的初始化列表只负责第一次创建变量时初始化函数体内只是普通赋值运算随便覆盖多少次都没问题不受 “只能出现一次” 限制。引用成员变量const 成员变量没有默认构造的类类型变量必须放在初始化列表位置进行初始化否则会编译报错。原因const 成员变量必须初始化不可二次赋值const 修饰的变量一旦创建就不能修改不存在 “先默认初始化、再函数内赋值” 的操作空间。classTest{public:constintnum;// const成员Test(intx){numx;// 错误num已经默认初始化不能赋值修改const}};intmain(){Testt(10);return0;}引用本质是别名不存在空引用、不存在默认引用对象创建时就必须绑定一个已存在的变量函数体内无法后期绑定。这时就会造成空引用。classTest{public:intref;// 引用成员Test(intx){refx;// 错误ref先默认构造非法空引用再赋值不允许}};intmain(){inta100;Testt(a);return0;}如果一个自定义类没有无参默认构造函数编译器不会自动生成默认构造当它作为另一个类的成员时无法自动初始化必须手动在初始化列表调用它的有参构造。classB{public:// 只有有参构造编译器不会生成默认构造 B()B(intdata){coutB有参构造dataendl;}};classA{public:B b;// B没有默认构造A(intx){bB(x);// 错误进入函数体前编译器尝试调用B()不存在直接报错}};正确案例// 无默认构造的类classB{public:B(intval){coutB构造valendl;}};classDemo{public:// 三种必须初始化列表的成员constintc_num;// const成员intref_num;// 引用成员B obj_b;// 无默认构造类成员// 正确全部在初始化列表初始化Demo(intc,intr,intb_val):c_num(c),ref_num(r),obj_b(b_val){// 函数体内只能做普通赋值不能初始化上面三类成员cout构造函数体执行endl;}};intmain(){intnum999;Demod(100,num,520);return0;}C11 支持在成员变量声明的位置给缺省值这个缺省值主要是给没有显式在初始化列表初始化的成员使用的。注意这里若初始化列表有赋值都优先使用初始化列表里的值。尽量使用初始化列表初始化因为那些你不在初始化列表初始化的成员也会走初始化列表如果这个成员在声明位置给了缺省值初始化列表会用这个缺省值初始化。如果你没有给缺省值对于没有显式在初始化列表初始化的内置类型成员是否初始化取决于编译器C 并没有规定。**即有类内就地缺省值C11用缺省值初始化内置类型无缺省值标准不强制初始化值是随机垃圾。**对于没有显式在初始化列表初始化的自定义类型成员会调用这个成员类型的默认构造函数如果没有默认构造会编译错误。即无论怎样初始化列表都会进行初始化这样优先使用它可以提高效率。初始化列表中按照成员变量在类中声明顺序进行初始化跟成员在初始化列表出现的先后顺序无关。建议声明顺序和初始化列表顺序保持一致。先初始化 a类中第一个声明初始化列表写 a(b)但此时 b 还未初始化b 是内存随机垃圾值 → a 随机脏数。再初始化 b赋值传入的 100 → b 1003.总结无论是否显式写初始化列表每个构造函数都有初始化列表无论是否在初始化列表显式初始化成员变量每个成员变量都要走初始化列表初始化。4.补充对于自定义成员变量的初始化列表的使用通常是因为其没有默认构造函数。在使用初始化列表时我们不应该直接传递整个变量而是给自定义成员变量传递参数进行赋值。// 自定义类只有带参构造无默认构造classBook{public:string name;Book(string n):name(n){}};classShop{public:Book b;Shop():b(C编程){}};还有一点内容放到后面讲解请关注我的主页。

相关新闻

2026衡阳黄金回收白银回收铂金回收靠谱临街实体公安备案支持到店核验门店联系方式推荐

2026衡阳黄金回收白银回收铂金回收靠谱临街实体公安备案支持到店核验门店联系方式推荐

2026衡阳黄金白银铂金回收实测榜单|公安备案临街实体中检认证无折旧费门店 依托衡阳本地落笔,小编实地走访发现,衡阳贵金属回收店铺遍地丛生,但行业套路层出不穷,不少市民变现遭遇虚高报价、克扣损耗、未经同意熔金压价…

2026/7/29 20:45:51 阅读更多 →
科技早报(第2026-07-17.md期):变现加速监管升温

科技早报(第2026-07-17.md期):变现加速监管升温

国内外 AI 与科技领域当日要闻摘要 含 6 条深度热点解读 今日要点速览 欧盟援引 DMA 勒令 Google 向 AI 竞争对手开放 Android 系统Netflix 首度披露:约 300 部作品使用生成式 AI,主要在后期制作环节Epic Games 将向 Fortnite 创作者开放 36 个 AI 语音…

2026/7/31 4:47:20 阅读更多 →
Flash存储器物理结构解析与开发实践

Flash存储器物理结构解析与开发实践

1. Flash存储器的物理结构基础 在嵌入式系统和存储设备中,Flash存储器是最常见的非易失性存储介质之一。理解其物理组织结构对于开发者进行底层编程、性能优化和故障排查至关重要。Flash芯片的物理结构采用分层设计,从大到小依次为:块(Block)…

2026/7/29 2:49:05 阅读更多 →

最新新闻

Hermes Cron 定时任务未执行:用三层只读诊断定位故障

Hermes Cron 定时任务未执行:用三层只读诊断定位故障

Hermes Cron 定时任务未执行:用三层只读诊断定位故障透明说明:本文由 AI 辅助整理,命令、事实与发布内容仍需作者复核。Hermes Cron 任务没有按时产生结果时,不宜直接重跑。更可靠的处理顺序是先确认调度器是否可用,再…

2026/7/31 21:03:37 阅读更多 →
“触探深海”远古生命演化特展上海站:跟随时空双重线索,开启海洋生命演化的探索之旅

“触探深海”远古生命演化特展上海站:跟随时空双重线索,开启海洋生命演化的探索之旅

“我们从哪里来?”数亿年前的古生代,生命悄然在深海中诞生,书写地球生命演化史上最初的序章。从水中潜行到踏足陆地,生命在演化的长河中不断变化形态,在持续的跃迁中构建无尽可能。“触探深海”远古生命演化特展上海站…

2026/7/31 21:03:37 阅读更多 →
7月AI效率工具产品化全月复盘:PMF验证的30个关键发现与8月行动计划

7月AI效率工具产品化全月复盘:PMF验证的30个关键发现与8月行动计划

7月AI效率工具产品化全月复盘:PMF验证的30个关键发现与8月行动计划 作者:钟伊人(钟哩哩)日期:2026年7月31日标签:AI产品化、PMF验证、效率工具、创业复盘 模块一:复盘背景与PMF评估框架 7月是A…

2026/7/31 21:03:37 阅读更多 →
模型部署工程的下半年路线图:从技术选型到团队能力建设

模型部署工程的下半年路线图:从技术选型到团队能力建设

模型部署工程的下半年路线图:从技术选型到团队能力建设 一、下半年部署工程的宏观趋势 2026年下半年,模型部署工程面临三个宏观趋势的交汇。第一,模型架构的多样化——Transformer、SSM、MoE和混合架构的并行使推理引擎需要支持更多种类的算…

2026/7/31 21:03:37 阅读更多 →
7月Transformers架构进展月报:论文、开源项目与社区动态

7月Transformers架构进展月报:论文、开源项目与社区动态

7月Transformers架构进展月报:论文、开源项目与社区动态 一、7月论文的关键信号 2026年7月,Transformers相关研究的arXiv投稿呈现出几个值得关注的信号。最显著的趋势是"混合架构"论文的占比持续上升——在7月cs.CL和cs.LG子领域的Transform…

2026/7/31 21:03:37 阅读更多 →
三分钟上手Whisky:让Windows程序在macOS上原生运行的终极方案

三分钟上手Whisky:让Windows程序在macOS上原生运行的终极方案

三分钟上手Whisky:让Windows程序在macOS上原生运行的终极方案 【免费下载链接】Whisky A modern Wine wrapper for macOS built with SwiftUI 项目地址: https://gitcode.com/gh_mirrors/wh/Whisky 还在为macOS上无法运行Windows专属软件而烦恼吗&#xff1f…

2026/7/31 21:02:37 阅读更多 →

日新闻

物理复制比逻辑复制好在哪?数据库复制原理详解

物理复制比逻辑复制好在哪?数据库复制原理详解

数据库复制是把主库数据同步到备库的机制,分为逻辑复制和物理复制两种。逻辑复制传输的是 SQL 语句或行变更事件,物理复制传输的是存储引擎底层的物理日志。阿里云 PolarDB(云原生数据库)采用物理复制,在同步延迟、数据…

2026/7/31 0:00:34 阅读更多 →
BilibiliDown:3分钟学会B站视频下载的终极指南

BilibiliDown:3分钟学会B站视频下载的终极指南

BilibiliDown:3分钟学会B站视频下载的终极指南 【免费下载链接】BilibiliDown (GUI-多平台支持) B站 哔哩哔哩 视频下载器。支持稍后再看、收藏夹、UP主视频批量下载|Bilibili Video Downloader 😳 项目地址: https://gitcode.com/gh_mirrors/bi/Bilib…

2026/7/31 0:00:34 阅读更多 →
有哪些游戏数据AI平台?游戏行业Data+AI融合方案盘点

有哪些游戏数据AI平台?游戏行业Data+AI融合方案盘点

当前,游戏行业的“DataAI融合”已从概念验证进入价值落地阶段。根据IDC 2025年数据,中国AI游戏云市场规模已达18.6亿元;同时,游戏研发环节AI渗透率高达86%,生成式AI内容普及率超过50%。面对庞大的市场,游戏…

2026/7/31 0:00:34 阅读更多 →

周新闻

深度学习道路桥梁裂缝检测系统 道路桥梁裂缝检测数据集 道路桥梁病害识别检测数据集

深度学习道路桥梁裂缝检测系统 道路桥梁裂缝检测数据集 道路桥梁病害识别检测数据集

深度学习道路桥梁裂缝检测系统 数据集6000张 完整源码已标注数据集训练好的模型环境配置教程程序运行说明文档,可以直接使用!系统支持图片、视频、摄像头等多种方式检测裂缝,功能强大实用。 1数据集6000张 8各类别

2026/7/31 1:03:03 阅读更多 →
深度学习YOLO模型如何训练 PUBG 绝地求生目标检测数据集

深度学习YOLO模型如何训练 PUBG 绝地求生目标检测数据集

pubg数据集 精选原图1.42万数据 1.49万标签 无任何重复、算法增强或冗余图像! pubg绝地求生目标检测数据集 1分类:e_body,14905个标签,txt格式 共计14244张图,99%为640*640尺寸图像 适合yolo目标检测、AI训练关键词&am…

2026/7/29 14:34:28 阅读更多 →
Apex英雄目标检测数据集 深度学习框架YOLO如何训练APEX数据集

Apex英雄目标检测数据集 深度学习框架YOLO如何训练APEX数据集

Apex检测数据集数据集详情检测类别: allies enemy tag图片总量:7247张训练集:5139张验证集:1425张测试集:683张标注状态:全部已标注,即拿即用数据格式:支持YOLO格式及其他格式&#…

2026/7/31 4:19:39 阅读更多 →

月新闻