【C++】透析类和对象(下)

有不懂的可以翻阅我之前文章!

                     个人主页:CSDN_小八哥向前冲

                      所属专栏:CSDN_C++入门


目录

拷贝构造函数

运算符重载

赋值运算符重载

取地址运算符重载

const成员函数

取地址重载

再探构造函数

初始化列表

类型转换

static成员

友元

内部类

匿名对象

对象拷贝时的编译器优化

日期类的实现

Date.h文件

Data.cpp文件


拷贝构造函数

拷贝构造的特点:

  1. 拷⻉构造函数是构造函数的⼀个重载。
  2. . 拷⻉构造函数的参数只有⼀个且必须是类类型对象的引⽤,使⽤传值⽅式编译器直接报错,因为语 法逻辑上会引发⽆穷递归调⽤
  3. C++规定⾃定义类型对象进⾏拷⻉⾏为必须调⽤拷⻉构造,所以这⾥⾃定义类型传值传参和传值返 回都会调⽤拷⻉构造完成。
  4. 若未显式定义拷⻉构造,编译器会⽣成⾃动⽣成拷⻉构造函数。⾃动⽣成的拷⻉构造对内置类型成员变量会完成值拷⻉/浅拷⻉(⼀个字节⼀个字节的拷⻉),对⾃定义类型成员变量会调⽤他的拷⻉构造。
  5. 传值返回会产⽣⼀个临时对象调⽤拷⻉构造,传值引⽤返回,返回的是返回对象的别名(引⽤),没 有产⽣拷⻉。但是如果返回对象是⼀个当前函数局部域的局部对象,函数结束就销毁了,那么使⽤ 引⽤返回是有问题的,这时的引⽤相当于⼀个野引⽤,类似⼀个野指针⼀样。传引⽤返回可以减少 拷⻉,但是⼀定要确保返回对象,在当前函数结束后还在,才能⽤引⽤返回。

拷贝构造参数必须用引用,否则编译错误,因为会引发无穷递归的拷贝构造!

如图:

运算符重载

运算符重载特点:

  1. 运算符重载是具有特名字的函数,他的名字是由operator和后⾯要定义的运算符共同构成。和其他 函数⼀样,它也具有其返回类型和参数列表以及函数体。
  2. 重载运算符函数的参数个数和该运算符作⽤的运算对象数量⼀样多。⼀元运算符有⼀个参数,⼆元 运算符有两个参数,⼆元运算符的左侧运算对象传给第⼀个参数,右侧运算对象传给第⼆个参数。
  3. 如果⼀个重载运算符函数是成员函数,则它的第⼀个运算对象默认传给隐式的this指针,因此运算 符重载作为成员函数时,参数⽐运算对象少⼀个。
  4.    .*    : :    sizeof   ?:     . ) 注意以上5个运算符不能重载。
  5. 重载++运算符时,有前置++和后置++,运算符重载函数名都是operator++,⽆法很好的区分。 C++规定,后置++重载时,增加⼀个int形参,跟前置++构成函数重载,⽅便区分。
  6. 重载>>和<<时,需要重载为全局函数,因为重载为成员函数,this指针默认抢占了第⼀个形参位置,第⼀个形参位置是左侧运算对象,调⽤时就变成了对象<<cout,不符合使⽤习惯和可读性。重载为全局函数把ostream/istream放到第⼀个形参位置就可以了,第⼆个形参位置当类类型对象

前置++和后置++的区别:

赋值运算符重载

赋值运算符重载注意事件:

  1. 赋值运算符重载是⼀个运算符重载,规定必须重载为成员函数。赋值运算重载的参数建议写成 const 当前类类型引⽤,否则会传值传参会有拷⻉
  2. 有返回值,且建议写成当前类类型引⽤,引⽤返回可以提⾼效率,有返回值⽬的是为了⽀持连续赋 值场景。
  3. 没有显式实现时,编译器会⾃动⽣成⼀个默认赋值运算符重载,默认赋值运算符重载⾏为跟默认构 造函数类似,对内置类型成员变量会完成值拷⻉/浅拷⻉(⼀个字节⼀个字节的拷⻉),对⾃定义类型 成员变量会调⽤他的拷⻉构造。

参数和返回值写成引用的形式的原因:

可以提高效率,避免拷贝,因为传值传参会有拷贝!

注意:

  1. 当只是简单的赋值运算(浅拷贝),那么可以不写这个赋值重载,编译器自身的就能解决!
  2. 当需要深层次的拷贝(涉及指针指向空间的这种),那么就要自己实现赋值函数!

还有一种情况赋值重载会和拷贝构造混淆:

取地址运算符重载

const成员函数

特点:

  1. 将const修饰的成员函数称之为const成员函数,const修饰成员函数放到成员函数参数列表的后 ⾯
  2. const实际修饰该成员函数隐含的this指针,表明在该成员函数中不能对类的任何成员进⾏修改。

不管变量还是函数利用const 修饰都有一个共同的特点:不变。

值得我们注意的是——不能权限扩大

取地址重载

取地址运算符重载分为普通取地址运算符重载和const取地址运算符重载,⼀般这两个函数编译器⾃动⽣成的就可以够我们⽤了,不需要去显⽰实现。除⾮⼀些很特殊的场景,⽐如我们不想让别⼈取到当 前类对象的地址,就可以⾃⼰实现⼀份,胡乱返回⼀个地址。

这个不怎么常用,我们不做过多的介绍。

再探构造函数

初始化列表

内容:

  1. 之前我们实现构造函数时,初始化成员变量主要使⽤函数体内赋值,构造函数初始化还有⼀种⽅式,就是初始化列表,初始化列表的使⽤⽅式是以⼀个冒号开始,接着是⼀个以逗号分隔的数据成 员列表,每个"成员变量"后⾯跟⼀个放在括号中的初始值或表达式。
  2. 每个成员变量在初始化列表中只能出现⼀次,语法理解上初始化列表可以认为是每个成员变量定义 初始化的地⽅。
  3. 引⽤成员变量,const成员变量,没有默认构造的类类型变量,必须放在初始化列表位置进⾏初始化,否则会编译报错。
  4. C++11⽀持在成员变量声明的位置给缺省值,这个缺省值主要是给没有显⽰在初始化列表初始化的 成员使⽤的。
  5. 尽量使⽤初始化列表初始化,因为那些你不在初始化列表初始化的成员也会⾛初始化列表,如果这 个成员在声明位置给了缺省值,初始化列表会⽤这个缺省值初始化。如果你没有给缺省值,对于没 有显⽰在初始化列表初始化的内置类型成员是否初始化取决于编译器,C++并没有规定。对于没有 显⽰在初始化列表初始化的⾃定义类型成员会调⽤这个成员类型的默认构造函数,如果没有默认构 造会编译错误。
  6. 初始化列表中按照成员变量在类中声明顺序进⾏初始化,跟成员在初始化列表出现的的先后顺序⽆ 关。建议声明顺序和初始化列表顺序保持⼀致。

第三点的原因:

因为这三种类型变量定义时必须要初始化,否则就报错!

初始化列表的使用形式:

初始化列表初始化数据规则:

我们来看个题目:

类型转换

  1. C++⽀持内置类型隐式类型转换为类类型对象,需要有相关内置类型为参数的构造函数。
  2. 构造函数前⾯加explicit就不再⽀持隐式类型转换。

static成员

内容:

  1. ⽤static修饰的成员变量,称之为静态成员变量静态成员变量⼀定要在类外进⾏初始化。(可以在类里面声明)。
  2. 静态成员变量为所有类对象所共享,不属于某个具体的对象,不存在对象中,存放在静态区
  3. ⽤static修饰的成员函数,称之为静态成员函数,静态成员函数没有this指针
  4. 静态成员函数中可以访问其他的静态成员,但是不能访问⾮静态的,因为没有this指针
  5. ⾮静态的成员函数,可以访问任意的静态成员变量和静态成员函数。
  6. 突破类域就可以访问静态成员,可以通过类名::静态成员或者对象.静态成员来访问静态成员变量 和静态成员函数。
  7. 静态成员也是类的成员,受public、protected、private访问限定符的限制
  8. 静态成员变量不能在声明位置给缺省值初始化因为缺省值是个构造函数初始化列表的,静态成员 变量不属于某个对象,不⾛构造函数初始化列表

看题:

友元

  1. 友元提供了⼀种突破类访问限定符封装的⽅式,友元分为:友元函数和友元类,在函数声明或者类 声明的前⾯加friend,并且把友元声明放到⼀个类的⾥⾯。
  2. 外部友元函数可访问类的私有和保护成员,友元函数仅仅是⼀种声明,他不是类的成员函数
  3. 友元函数可以在类定义的任何地⽅声明,不受类访问限定符限制。
  4. ⼀个函数可以是多个类的友元函数。
  5. 友元类中的成员函数都可以是另⼀个类的友元函数,都可以访问另⼀个类中的私有和保护成员。
  6. 友元类的关系是单向的,不具有交换性,⽐如A类是B类的友元,但是B类不是A类的友元。
  7. 友元类关系不能传递,如果A是B的友元,B是C的友元,但是A不是B的友元。
  8. 有时提供了便利。但是友元会增加耦合度,破坏了封装,所以友元不宜多⽤

内部类

  1. 如果⼀个类定义在另⼀个类的内部,这个内部类就叫做内部类。内部类是⼀个独⽴的类,跟定义在 全局相⽐,他只是受外部类类域限制和访问限定符限制,所以外部类定义的对象中不包含内部类。
  2. 内部类默认是外部类的友元类。
  3. 内部类本质也是⼀种封装,当A类跟B类紧密关联,A类实现出来主要就是给B类使⽤,那么可以考 虑把A类设计为B的内部类,如果放到private/protected位置,那么A类就是B类的专属内部类,其 他地⽅都⽤不了

匿名对象

  • ⽤类型(实参)定义出来的对象叫做匿名对象,相⽐之前我们定义的类型对象名(实参)定义出来的 叫有名对象。
  • 匿名对象⽣命周期只在当前⼀⾏,⼀般临时定义⼀个对象当前⽤⼀下即可,就可以定义匿名对象。

对象拷贝时的编译器优化

  1. 现代编译器会为了尽可能提⾼程序的效率,在不影响正确性的情况下会尽可能减少⼀些传参和传参过程中可以省略的拷⻉。
  2. 如何优化C++标准并没有严格规定,各个编译器会根据情况⾃⾏处理。当前主流的相对新⼀点的编 译器对于连续⼀个表达式步骤中的连续拷⻉会进⾏合并优化,有些更新更"激进"的编译还会进⾏跨 ⾏跨表达式的合并优化。

我们知道传值传参会进行拷贝构造,如果很多地方我们都不用引用的话,就会出现大量的拷贝构造,这时候编译器会优化,直接跳过临时对象这一步骤,直接构造!

日期类的实现

那么我们类和对象就已经全部搞定!

我们来实现一个日期类巩固一下!比较简单,我们就不做过多解释,直接上代码!

Date.h文件

#include<iostream>
using namespace std;
#include<assert.h>namespace ywc
{class Date{public:friend istream& operator>>(istream& in, Date& d);friend ostream& operator<<(ostream& out, Date& d);Date(int year=1,int month=1,int day=1):_year(year),_month(month),_day(day){if (!CheckDate()){cout << "日期非法" << endl;cout << *this;}}int GetMonthDay(){assert(_month < 13 && _month > 0);int MonthDay[] = { -1,31,28,31,30,31,30,31,31,30,31,30,31 };if (_month == 2 && ((_year % 4 == 0 && _year % 100 != 0) || (_year % 400 == 0))){return 29;}return MonthDay[_month];}bool CheckDate(){if (_year > 0){if (_month > 0 && _month < 13){if (_day > 0 && _day <= GetMonthDay()){return true;}}}return false;}~Date(){_year = _month = _day = 0;}//日期+/-天数Date operator+(int day);Date operator-(int day);Date& operator+=(int day);Date& operator-=(int day);//前置++Date operator++();Date& operator++(int);//日期-日期int operator-(Date& d);//日期比较大小bool operator==(Date& d);bool operator<(Date& d);bool operator>(Date& d);bool operator<=(Date& d);bool operator>=(Date& d);bool operator!=(Date& d);private:int _year;int _month;int _day;};//全局输入输出函数istream& operator>>(istream& in, Date& d);ostream& operator<<(ostream& out, Date& d);
}

Data.cpp文件

#include"Date.h"namespace ywc
{Date& Date::operator+=(int day){if (day < 0){return *this -= (-day);}_day += day;while (_day > GetMonthDay()){_day -= GetMonthDay();_month++;if (_month == 13){_month = 1;_year++;}}return *this;}Date Date::operator+(int day){Date tmp = *this;return tmp += day;}Date& Date::operator-=(int day){if (day < 0){return *this += (-day);}_day -= day;while (_day <= 0){_month--;if (_month == 0){_year--;_month = 12;}_day += GetMonthDay();}return *this;}Date Date::operator-(int day){Date tmp = *this;return tmp -= day;}int Date::operator-(Date& d){int flag = 1;Date max =*this, min = d;if (max < min){max = d;min = *this;flag = -1;}int n = 0;while (min!=max){++min;++n;}return n*flag;}Date Date::operator++(){Date tmp = *this;*this += 1;return tmp;}Date& Date::operator++(int){return (*this += 1);}bool Date::operator==(Date& d){if (_year == d._year && _month == d._month && _day == d._day){return true;}return false;}bool Date::operator!=(Date& d){return !(*this == d);}bool Date::operator<(Date& d){if (_year < d._year){return true;}else if(_year==d._year){if (_month < d._month){return true;}else if (_month == d._month){if (_day < d._day){return true;}}}return false;}bool Date::operator>(Date& d){return !(*this < d);}bool Date::operator<=(Date& d){return *this < d || *this == d;}bool Date::operator>=(Date& d){return *this > d || *this == d;}istream& operator>>(istream& in, Date& d){in >> d._year >> d._month >> d._day;while (!d.CheckDate()){cout << "日期非法,请重新输入" << endl;in >> d._year >> d._month >> d._day;}return in;}ostream& operator<<(ostream& out, Date& d){out << d._year << "年" << d._month << "月" << d._day << "日";return out;}
}

相信看到这里你已经收获满满了,我们下期见!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/3269804.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

【CN】Argo 持续集成和交付(一)

1.简介 Argo 英 [ˈɑ:ɡəu] 美 [ˈɑrˌɡo] Kubernetes 原生工具&#xff0c;用于运行工作流程、管理集群以及正确执行 GitOps。 Argo 于 2020 年 3 月 26 日被 CNCF 接受为孵化成熟度级别&#xff0c;然后于 2022 年 12 月 6 日转移到毕业成熟度级别。 argoproj.github.i…

(最全最小白易懂版)Yolov8新手教程-配置环境、数据集处理、目标检测、结果分析处理(图像指标、可视化结果)、报错分析等全过程学习记录

目录 一、安装环境&#xff08;配置yolo、demo测试&#xff09; 二、数据集准备&#xff08;格式学习&#xff09; 三、训练数据集 1.划分数据集 2.训练数据集 2.1常规训练 2.2微调 3.各种报错记录 3.1AttributeError 3.2TypeError 3.3Error while loading conda en…

Flutter Dio网络请求报错FormatException: Unexpected character

最近开发Flutter项目&#xff0c;网络请求采用的是Dio框架&#xff0c;在发起网络请求的时候报错&#xff1a; 网络请求返回的数据为&#xff1a; var returnCitySN {\"cip\": \"127.0.0.1\", \"cid\": \"00\", \"cname\"…

浅谈 JVM 的内存划分、类加载、垃圾回收机制

文章目录 一、JVM内存划分1.1、JVM为什么要进行内存划分&#xff1f; 二、JVM类加载2.1、什么是类加载&#xff1f;2.2、类加载大体过程2.3、何时触发类加载&#xff1f;2.4、双亲委派模型[!面试高频问题]2.4.1、类加载器2.4.1、什么是双亲委派模型&#xff1f; 三、JVM 垃圾回…

Flink SQL 的工作机制

前言 Flink SQL 引擎的工作流总结如图所示。 从图中可以看出&#xff0c;一段查询 SQL / 使用TableAPI 编写的程序&#xff08;以下简称 TableAPI 代码&#xff09;从输入到编译为可执行的 JobGraph 主要经历如下几个阶段&#xff1a; 将 SQL文本 / TableAPI 代码转化为逻辑执…

书生大模型实战营--L1关卡-OpenCompass 评测 InternLM-1.8B 实践

一、使用 OpenCompass 评测 internlm2-chat-1.8b 模型在 MMLU 数据集上的性能 1、使用lmdeploy部署 internlm2-chat-1.8b模型 2、根据OpenCompass官网教程安装并下载数据集 opencompass/README_zh-CN.md at main open-compass/opencompass GitHub 注意&#xff1a; pyhton…

【Java】this关键字、构造方法、标准javabean类(009)

目录 ♦️构造方法 &#x1f383;无参数构造方法&#xff08;空参构造&#xff09; &#x1f383;有参数构造方法 ♦️this关键字 &#x1f383;就近原则 &#x1f383;使用this关键字调用本类中的属性 ​编辑 &#x1f383;使用this关键字调用成员方法 ​编辑 &#x…

Collention集合基础知识

Array 数组是一种连续的内存空间存储相同数据类型数据的线性数据结构 数组获取其他元素的地址值 寻址公式 a[i] baseaddress i*datatypesize 为什么数组索引从0开始 从1开始不行吗 从0开始寻址公式 a[i] baseaddress i*datatypesize 从1开始寻址公式 a[i] baseadd…

【计算机网络】无线网络和移动网络(第9章)大纲(共70+页)

最后只复习了1.5天&#xff0c;应用层简单过了一遍。 本来是mindmap的&#xff0c;但是太大了只能导出成提纲了&#xff0c;凑合看吧orz。 如果你找我要源文件&#xff0c;最好是在2024年&#xff0c;不然我可能就找不到了&#xff08;&#xff09;。

基于STC8H系列单片机的中断系统

基于STC8H系列单片机的中断系统 STC8H4K64TL单片机介绍STC8H4K64TL单片机管脚图(48个引脚)STC8H4K64TL单片机串口仿真与串口通信STC8H4K64TL单片机管脚图(32个引脚)STC8H4K64TL单片机管脚图(20个引脚)STC8H系列单片机管脚说明STC8H系列单片机I/O口STC8H系列单片机I/O口相…

【C++】:红黑树的应用 --- 封装map和set

点击跳转至文章&#xff1a;【C】&#xff1a;红黑树深度剖析 — 手撕红黑树&#xff01; 目录 前言一&#xff0c;红黑树的改造1. 红黑树的主体框架2. 对红黑树节点结构的改造3. 红黑树的迭代器3.1 迭代器类3.2 Begin() 和 End() 四&#xff0c;红黑树相关接口的改造4.1 Find…

centos stream 9安装 Kubernetes v1.30 集群

1、版本说明&#xff1a; 系统版本&#xff1a;centos stream 9 Kubernetes版本&#xff1a;最新版(v1.30) docker版本&#xff1a;27.1.1 节点主机名ip主节点k8s-master172.31.0.10节点1k8s-node1172.31.0.11节点2k8s-node2172.31.0.12 2、首先&#xff0c;使用Vagrant和Virt…

【2024年国际高等学校数学建模竞赛IMMCHE】问题 B:太空移民计划和战略 问题分析及数学模型及求解代码

【2024年国际高等学校数学建模竞赛IMMCHE】问题 B&#xff1a;太空移民计划和战略 问题分析及数学模型及求解代码 Problem B: Space Migration Program and Strategy 1 题目 我们的未来有两种可能&#xff1a;第一&#xff0c;我们将留在地球上&#xff0c;直到完全灭绝&…

Hive3:Hive初体验

1、创建表 CREATE TABLE test(id INT, name STRING, gender STRING);2、新增数据 INSERT INTO test VALUES(1, 王力红, 男); INSERT INTO test VALUES(2, 钉钉盯, 女); INSERT INTO test VALUES(3, 咔咔咔, 女);3、查询数据 简单查询 select * from test;带聚合函数的查询 …

Halcon 引擎方式调试

1.C# 端添加代码 启动调试模式 public HDevEngine MyEngine new HDevEngine(); // halcon引擎;// 启动调试服务 MyEngine.StartDebugServer();2.Halcon程序添加到进程 打开Halcon程序 【执行】>【附加到进程】 点击【确定】 3.C# 程序执行到相关位置 C# 程序执行调用…

vector深度剖析及模拟实现

目录 前言vector核心框架模拟实现1. 前期准备2. 构造和销毁补充: 隐式类型转换和多参数构造的区别 3. 迭代器相关4. 容器相关补充: memcpy拷贝问题 5. 元素访问6. vector的修改测试代码 总结 前言 本文重点模拟实现vector的核心接口, 帮助我们更好的理解底层逻辑, 以及对vecto…

科学又省力 宠物浮毛怎么去掉便捷高效?除毛秘籍养宠空气净化器

上次和朋友逛完街去她家&#xff0c;她家的猫哈基米一开门就飞奔过来&#xff0c;朋友直接抱起它狂亲。结果&#xff0c;猫毛和汗水粘得到处都是&#xff0c;手臂上、脸上都是&#xff0c;看得我这鼻炎星人直起鸡皮疙瘩。很多养宠物的朋友都说&#xff0c;天天给猫狗梳毛&#…

Android Studio导入源码

在有源码并且编译环境可用的情况下&#xff1a; 1.生成导入AS所需的配置文件 在源码的根目录执行以下命令&#xff1a; source build/ensetup.sh lunch 要编译的项目 make idegen //这一步会生成out/host/linux-x86/framework/idegen.jar development/tools/idegen/idegen.sh…

利用OSMnx求路网最短路径并可视化(二)

书接上回&#xff0c;为了增加多路径的可视化效果和坐标匹配最近点来实现最短路可视化&#xff0c;我们使用图形化工具matplotlib结合OSMnx的绘图功能来展示整个路网图&#xff0c;并特别高亮显示计算出的最短路径。 多起终点最短路路径并计算距离和时间 完整代码#运行环境 P…

《昇思25天学习打卡营第24天|基于MindSpore通过GPT实现情感分类》

基于MindSpore通过GPT实现情感分类 %%capture captured_output # 实验环境已经预装了mindspore2.2.14&#xff0c;如需更换mindspore版本&#xff0c;可更改下面mindspore的版本号 !pip uninstall mindspore -y !pip install -i https://pypi.mirrors.ustc.edu.cn/simple mind…