新闻详情

新闻详情

首页 / 资讯中心 / 详情

把C++类包装成真正可用的对象:运算符重载、const、静态成员

发布时间:2026/9/28 20:25:45来源:尧图网络
把C++类包装成真正可用的对象:运算符重载、const、静态成员
代码仓库《C日期类的实现》文章目录1. 为什么要重载运算符2. 运算符重载的基本规则2.1 一个简单的比较运算符2.2 成员函数还是非成员函数3. 返回引用还是返回对象4. 前置 和后置 5. const 成员函数承诺不修改对象6. 静态成员属于类的共享数据7. 友元有边界地打破访问限制8. 类型转换与 explicit9. 内部类和匿名对象9.1 内部类嵌套类9.2 匿名对象10. 小结前两篇解决了“类是什么”和“对象如何管理生命周期”。这一篇继续回答怎样让自定义类型用起来更自然同时保持接口清晰、状态可靠。1. 为什么要重载运算符假设有两个日期对象Datetoday(2026,9,24);Datetomorrow(2026,9,25);如果没有运算符重载我们可能只能写//判断当前日期是否在指定日期之前today.IsBefore(tomorrow);//给当前日期加一天today.AddDays(1);这当然可以但日期本身已经是一个有明确值语义的类型。下面的表达式可能更加符合常规使用todaytomorrow;today1;today;运算符重载不是发明新运算符只是给 C 已有的运算符增加对自定义类类型的处理逻辑。以下是一些运算符重载需要遵守的规则不能新增运算符不能自创符号。不能修改运算符原有属性比如永远是二元运算符不能改成单目。优先级不变结合性不变操作数数量不变。至少有一个操作数必须是自定义类 / 枚举类型不能只重载内置类型不能改intint行为。有几个运算符不能重载::作用域解析、.成员访问、.*成员指针访问、?:三目运算符、sizeof。运算符重载不会创建新运算符只是扩展已有运算符对自定义类型的行为。目的提升可读性让自定义类型像内置类型一样使用表达式。2. 运算符重载的基本规则2.1 一个简单的比较运算符classPoint{public:Point(intx0,inty0):_x(x),_y(y){}booloperator(constPointother)const{return_xother._x_yother._y;}private:int_x;int_y;};调用Pointa(1,2);Pointb(1,2);std::cout(ab)std::endl;a b可以理解为a.operator(b);运算符重载函数至少有一个参数涉及自定义类型不能通过重载改变两个内置类型之间的含义也不能写出语言中不存在的operator。2.2 成员函数还是非成员函数比较运算符通常可以写成成员函数因为左操作数天然对应 thisboolDate::operator(constDateother)const;而流插入希望写成std::cout date左边是输出流右边才是日期。此时通常把它写成类外函数并通过友元访问私有成员std::ostreamoperator(std::ostreamout,constDatedate);3. 返回引用还是返回对象修改当前对象的运算符通常返回当前对象的引用classCounter{public:Counteroperator(intvalue){_valuevalue;return*this;}private:int_value0;};会直接修改自己this 指向的当前对象返回Counter、return *this目的支持链式连续调用如a 1 2*this是当前对象生命周期在函数调用结束后仍然存在返回引用是安全的当产生了新结果而不修改当前对象的运算符通常返回对象Dateoperator(intdays)const{Date result*this;resultdays;returnresult;}普通不改动原来的 this 对象新建局部对象result保存计算结果result是函数内部局部变量函数结束后result会销毁不能返回Date result会返回野引用引用指向已经销毁的局部对象未定义行为。返回Date值返回会把 result 拷贝返回给外部调用方。函数加const因为不会修改当前对象符合 const 成员函数规范4. 前置 和后置 classCounter{public:// 前置 counterCounteroperator(){_value;return*this;}// 后置 counterCounteroperator(int){Counter old*this;_value;returnold;}private:int_value0;};前置逻辑先修改对象返回修改后自身的引用返回Counter引用安全*this是当前对象函数结束对象还存在支持链式运算(counter)行为和内置类型i完全一致后置那个int 是占位参数只用来区分重载版本调用时可以不需要传实参编译器会自动识别。逻辑先拷贝保存旧值 - 修改当前对象 - 返回旧副本返回类型是Counter对象不是引用old是函数内局部临时对象函数结束就销毁不能返回引用只能按值返回。后置版本多出的 int 只是为了和前置版本区分调用时不需要传这个参数。前置版本先修改再返回当前对象后置版本先保存旧值再修改当前对象最后返回旧值。写法修改时机返回结果counter先修改修改后的对象counter先保存旧值再修改修改前的对象5. const 成员函数承诺不修改对象classDate{public:voidPrint()const{std::cout_year/_month/_daystd::endl;}voidAddDay(){_day;}private:int_year0;int_month0;int_day0;};const放在成员函数参数列表后面表示该函数不会修改当前对象的数据成员。可以把隐含的this从Date* const理解为更严格的const Date* const。因此const对象只能调用const成员函数constDatedate(2026,9,24);date.Print();// 正确date.AddDay();// 错误可能修改对象const成员函数内部只能调用其他const成员函数不能调用非const成员函数因为非const函数可能修改对象这也体现出了权限的严格只能缩小不能放大。只读操作如Print、比较、获取成员值通常应该声明为const。如果忘记加const普通对象能调用但const对象无法调用在后续实现一些组合表达式时可能会受到限制。6. 静态成员属于类的共享数据普通成员变量属于每一个对象静态成员变量属于整个类所有对象共享同一份classStudent{public:Student(){_count;}~Student(){--_count;}staticintCount(){return_count;}private:staticint_count;};intStudent::_count0;使用std::coutcountStudent::Count()std::endl;Student a;Student b;std::coutcountStudent::Count()std::endl;运行示例代码创建了 a、b 两个对象构造函数各执行一次_count共享同一个静态变量所以计数变成 2。静态成员函数没有this指针所以不能直接访问普通成员变量但它可以访问静态成员。静态成员变量通常需要在类外提供定义不能只在类体内声明就结束。调用方式推荐Student::Count()类名::也可以用对象调用a.Count()但本质和对象无关。7. 友元有边界地打破访问限制友元函数不是类的成员函数但可以访问类的私有成员classPoint{friendvoidPrintPoint(constPointpoint);public:Point(intx,inty):_x(x),_y(y){}private:int_x;int_y;};voidPrintPoint(constPointpoint){std::coutpoint._x,point._ystd::endl;}friend声明写在类内部但PrintPoint不属于 Point 类没有 this 指针。它只是获得了 “访问 Point 私有成员” 的权限,但并不是成员函数不能用通过Point::PrintPoint()调用友元声明放在public/private/protected任意位置效果完全一样不影响。友元关系具有单向性A 是 B 的友元不代表 B 自动是 A 的友元。友元可以是全局函数也可以是别的类的成员函数也可以是整个类友元类friend class B友元破坏封装性不要滥用只用于关系紧密、无法作为成员函数的场景流运算符重载。8. 类型转换与 explicit单参数的构造函数可以让内置类型隐式转换为类对象classScore{public:Score(intvalue):_value(value){}private:int_value;};voidPrintScore(constScorescore){}PrintScore(100);// 隐式转换编译器自动用100构造临时Score对象传给函数如果这种转换不是你希望调用者无意间触发的可以在构造函数前加explicit修饰classScore{public:explicitScore(intvalue):_value(value){}private:int_value;};此时PrintScore(100);//编译报错不允许隐式转换PrintScore(Score(100));//显式调用构造明确写出转换允许不加explicit单参构造允许隐式转换加explicit只能显式构造禁止编译器偷偷自动转换。9. 内部类和匿名对象9.1 内部类嵌套类定义在另一个类里面的类叫内部类 / 嵌套类classOuter{public://内部类Inner只服务于OuterclassInner{public:voidfunc(){}};};内部类本质是独立的类不属于外部类对象内部类没有外部类的 this 指针默认情况下Inner不能直接访问Outer的普通成员如果要访问Outer成员需要拿到外部类对象的实例访问权限如果Inner写在Outer的private里外部代码不能直接Outer::Inner写在public外部可以Outer::Inner obj;内存sizeof(Outer)不会包含 Inner 的大小内部类只是类型声明不占外部对象内存。9.2 匿名对象匿名对象没有变量名用类型(实参)定义出来的对象一次性临时创建出来用完立刻销毁classSolution{public:intSum_Solution(intn){//...returnn;}};intmain(){intresSolution().Sum_Solution(10);return0;}生命周期语句结束就销毁典型场景函数传参、函数返回值、一次性测试。Java中用的很多10. 小结运算符重载的目标是让类型表达自然同时保持清晰的修改边界。const让只读接口能够被可靠地使用。静态成员表达属于类的共享状态。友元解决特定的协作关系。explicit防止不明确的类型转换。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

JavaWeb小说阅读管理系统源码解析:部署、核心功能与课设避坑指南 2026/9/28 21:58:25

JavaWeb小说阅读管理系统源码解析:部署、核心功能与课设避坑指南

简介:基于JavaWeb的小说阅读管理系统设计与实现源码及课设报告(95分以上)打包在此,面向需要完成课程设计、期末大作业的计算机相关专业学生。系统实现用户注册登录、首页书籍分类浏览(历史、都市、仙侠、奇幻&#xff…

阅读更多 →
零基础用海康VM教育版做视觉定位:从环境搭建到标定实战 2026/9/28 21:58:17

零基础用海康VM教育版做视觉定位:从环境搭建到标定实战

机器视觉这行有个很现实的门槛:软件授权。很多人想入门,卡在第一步——打开官网一看,商业版授权费用不低,加密狗又是一笔开销,还没开始学就先被劝退。海康VM的教育版算是给了一条活路,功能上做了合理裁剪&a…

阅读更多 →
无人机编队协同新选择:M-Robots OS与ROS实战对比 2026/9/28 21:58:17

无人机编队协同新选择:M-Robots OS与ROS实战对比

1. 无人机编队为什么需要一套新系统1.1 从单机飞控到编队协同的跨越搞过无人机编队的人都知道,单机飞控和编队协同完全是两个维度的工程。单机场景下,飞控只管自己这一亩三分地,姿态解算、位置控制、电机输出,跑通了就完事。但一旦…

阅读更多 →
手机本地部署大模型实战:从模型量化到Android/iOS推理优化 2026/9/28 21:57:35

手机本地部署大模型实战:从模型量化到Android/iOS推理优化

1. 手机跑大模型这件事,到底靠不靠谱先说结论:能跑,但别指望它替代云端服务。我前后在骁龙8 Gen 2的Android机和iPhone 15 Pro上折腾了差不多两个月,从最初的“这玩意儿真能跑?”到后来把本地模型接进自己的笔记工作流…

阅读更多 →
Agent-Native架构重构实战:设计原理、最小实现与避坑指南 2026/9/28 21:57:28

Agent-Native架构重构实战:设计原理、最小实现与避坑指南

这两年我经手了不少LLM项目,一个感受越来越明显:大多数团队口中的“AI化”,不过是在传统系统外面套了一层会说话的前端。2024年下半年我在做一个客服知识库系统,最初就是标准的RAG加聊天窗口,用户在右上角点开机器人&a…

阅读更多 →
Python电商评论情感分析全流程实战:从数据采集到模型训练 2026/9/28 21:57:28

Python电商评论情感分析全流程实战:从数据采集到模型训练

简介:基于Python的电商买家评论情感分析项目包,专为毕业设计、期末大作业和课程设计场景打造,代码注释详尽,即使完全没有项目经验的新手也能看懂每一步实现,曾获98分且深受导师认可。整个压缩包约54MB,内含…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉