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/10/10 4:09:26 阅读更多 →
科技早报(第2026-07-17.md期):变现加速监管升温

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

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

2026/10/13 8:55:16 阅读更多 →
Flash存储器物理结构解析与开发实践

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

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

2026/10/9 7:19:57 阅读更多 →

最新新闻

Hive substr中文乱码根源与5种实战解决方案

Hive substr中文乱码根源与5种实战解决方案

1. 项目概述:当Hive的substr遇上中文乱码,不是函数错了,是字符集在“说方言”你有没有遇到过这样的场景:一条日志字段里明明存着“用户_张三_20240516_订单完成”,用substr(col, 4, 6)想截出“张三”两个字&#xff0c…

2026/10/14 13:49:58 阅读更多 →
接口性能优化实战:从2秒到200ms的三层击破法

接口性能优化实战:从2秒到200ms的三层击破法

1. 这不是玄学,是可复现的接口性能优化实战“接口响应时间从2秒压到200毫秒以内”——这句话在很多技术团队的周会上被反复提起,听起来像一句目标口号,甚至带点理想主义色彩。但在我参与过的三个高并发业务系统重构中,它是一条必须…

2026/10/14 13:49:58 阅读更多 →
Hive substr中文乱码根源与字符安全截取方案

Hive substr中文乱码根源与字符安全截取方案

1. 项目概述:为什么一个看似简单的substr函数会突然在中文场景下“罢工”最近在某数据中台的日常ETL任务维护中,我连续三天被同一个报错堵在工位上:java.lang.StringIndexOutOfBoundsException: String index out of range,堆栈指…

2026/10/14 13:49:58 阅读更多 →
Ponytail 阅读进度条插件:滚动进度原理、接入与性能优化指南

Ponytail 阅读进度条插件:滚动进度原理、接入与性能优化指南

做内容站这几年,我一直有个执念:长文阅读体验不能只靠排版,还得给读者一点“进度反馈”。早先试过在文章顶部加一个手写的滚动进度条,但那种零散代码维护起来太麻烦,后来换成了开源的轻量级滚动进度插件,也…

2026/10/14 13:49:58 阅读更多 →
iOS容器底层探秘:NSMutableArray、NSDictionary、NSSet与NSCache深度解析

iOS容器底层探秘:NSMutableArray、NSDictionary、NSSet与NSCache深度解析

做iOS开发久了,数组、字典、集合这些容器天天在用,但真被人问一句NSMutableArray底层到底怎么扩容、NSDictionary凭什么查得那么快、NSCache和NSMutableDictionary除了线程安全还有什么本质区别、copy和mutableCopy的坑到底在哪,很多人会愣一…

2026/10/14 13:49:58 阅读更多 →
整车八自由度Simulink动力学模型搭建:从方程到仿真验证

整车八自由度Simulink动力学模型搭建:从方程到仿真验证

做整车动力学仿真的人,几乎都会经历从二自由度自行车模型起步,再逐步往多自由度模型走的过程。二自由度模型能把横摆和侧向运动的基本逻辑讲清楚,但一涉及到载荷转移、侧倾对轮荷分布的影响、四个车轮独立的转速动力学,它就完全不…

2026/10/14 13:48:57 阅读更多 →

日新闻

AnyPS5通用适配层设计:兼容性与性能的工程取舍

AnyPS5通用适配层设计:兼容性与性能的工程取舍

1. 从"AnyPS5"这个名字说起:它到底想解决什么问题第一次看到"AnyPS5"这个标题,我脑子里冒出来的第一个念头是:这大概率是一个围绕"跨平台运行"或者"通用适配"做文章的项目。名字里的"Any"…

2026/10/14 0:00:41 阅读更多 →
Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

1. 项目概述:Flutter跨平台二手交易应用开发作为一名长期从事移动应用开发的工程师,我最近完成了一个基于Flutter框架的二手物品交易平台项目。这个项目最吸引我的地方在于它完美结合了Flutter的跨平台优势与HarmonyOS的生态特性,实现了"…

2026/10/14 0:00:41 阅读更多 →
DFS算法解决飞机降落调度问题实战

DFS算法解决飞机降落调度问题实战

1. 项目背景与核心思路飞机降落问题是一个经典的调度优化场景,也是算法竞赛和面试中的高频题目。这个题目要求我们合理安排多架飞机的降落顺序和时间,确保所有飞机都能安全着陆而不发生冲突。在实际航空管制中,这类问题直接关系到飞行安全和机…

2026/10/14 0:00:41 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/13 16:22:04 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 22:01:27 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 7:53:34 阅读更多 →