【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://www.mzph.cn/web/49652.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MySQL查询执行(二):order by工作原理

假设你要查询城市是“杭州”的所有人名字&#xff0c; 并且按照姓名排序返回前1000个人的姓名、 年龄。 假设这个表的部分定义是这样的&#xff1a; -- 创建表t CREATE TABLE t (id int(11) NOT NULL,city varchar(16) NOT NULL,name varchar(16) NOT NULL,age int(11) NOT N…

Docker 搭建Elasticsearch详细步骤

本章教程使用Docker搭建Elasticsearch环境。 一、拉取镜像 docker pull docker.elastic.co/elasticsearch/elasticsearch:8.8.2二、运行容器 docker run -d --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-n

maven clean报错:Failed to delete xxxxx\target\xxxx.jar

问题描述 今天使用maven的clean命令时候出错如下&#xff1a; 分析问题 target文件可能时编译的文件被其他程序占用&#xff0c;导致资源无法回收 解决问题 1 打开任务管理器 右键任务栏。进入任务管理器 点击详细信息 2 进入 点击性能&#xff0c;点击打开资源监视器 …

推荐2024年大家都在用的4款ai写作免费神器

最近公司年中总结&#xff0c;要写好多像工作报告&#xff0c;工作计划之类的文件。我尝试着使用AI写作工具帮助&#xff0c;没想到效果意外的好&#xff0c;省事又省力。如果你也有和我一样的烦恼的话&#xff0c;可以去使用这4个写作工具&#xff0c;都是可以免费使用的。 1、…

错误代码0x80070035是什么情况?针对错误代码0x80070035的解决方法

错误代码 0x80070035 通常与网络连接和文件共享有关&#xff0c;表示“找不到网络路径”。这个问题可能由多种原因引起&#xff0c;包括网络设置不当、服务未启动、注册表配置错误等。今天这篇文章就和大家分享几种针对错误代码0x80070035的解决方法。 针对错误代码0x80070035问…

express连接mysql

一、 安装express npm install express --save二、express配置 //引入 const express require("express"); //创建实例 const app express(); //启动服务 app.listen(8081, () > {console.log("http://localhost:8081"); });三、安装mysql npm i m…

简过网:大学生考公,一定要先好好看看这篇文章!

大家好&#xff0c;我是简过网&#xff0c;今天这篇文章我们来聊聊关于大学生考公的那些事儿&#xff0c;希望能给大学生们一点点的帮助&#xff01; 首先&#xff0c;可能有朋友会问了&#xff0c;大学生一般从什么时候开始备考公务员呢&#xff0c;在这里小编建议大家从大三…

mysql1055报错解决方法

目录 一、mysql版本 二、 问题描述 三、解决方法 1.方法一&#xff08;临时&#xff09; 2.方法二&#xff08;永久&#xff09; 一、mysql版本 mysql版本&#xff1a;5.7.23 二、 问题描述 在查询时使用group by语句&#xff0c;出现错误代码&#xff1a;1055&#xf…

FastAPI(七十四)实战开发《在线课程学习系统》接口开发-- 删除留言

源码见&#xff1a;"fastapi_study_road-learning_system_online_courses: fastapi框架实战之--在线课程学习系统" 之前文章FastAPI&#xff08;七十三&#xff09;实战开发《在线课程学习系统》接口开发-- 回复留言&#xff0c;那么我们这次分享删除留言接口的开发…

MySQL可重复读的隔离机制下是否彻底解决了幻读?

答案&#xff1a;没有彻底解决。 一、什么是幻读&#xff1f; 当同一个查询在不同时间产生不同的结果集时&#xff0c;事务中就会出现幻读问题。 幻读关注的是记录数量的不同。 不可重复读关注的是记录内容的不同。 二、快照读和当前读 InnoDB引擎的默认隔离级别是可重复读&…

搭建自己的金融数据源和量化分析平台(四):自动化更新上市公司所属一级、二级行业以及股票上市状态

前面做了更新沪深交易所的上市股票列表的读取和更新&#xff0c;但一旦股票退市则需要在数据库里将该股票状态更新为退市&#xff0c;同时附上退市日期&#xff0c;将股票名更改为XX退。 此外深交所下载的xls解析出来是没有上市公司所属的二级行业的&#xff0c;因此还需要建立…

鸿蒙仓颉语言之【安全密码库crypto4cj】功能示例

功能示例 MD5使用样例 from crypto4cj import md5cj.*main() { var md: Array<UInt8> Array<UInt8>(16, item: 0)var result: String String(Array<Char>(33, item: 0))var str: String "helloworld"var ret md5(str.toUtf8Array(), md)r…

不支持jdk8的jenkins部署jdk8项目

1、背景 目前最新的jenkins必须基于jdk8以上&#xff0c;才能安装。jenkins最新的插件部分也不支持jdk8了。 2、全局工具配置 配置一个jdk8 配置一个jdk8以上的版本&#xff0c;如jdk17 3、部署maven项目 jdk17项目 可以直接使用maven插件&#xff0c;部署。 jdk8项目 由…

git等常用工具以及cmake

一、将git中的代码克隆进电脑以及常用工具介绍 1.安装git 首先需要安装git sudo apt install git 注意一定要加--recursive&#xff0c;因为文件中有很多“引用文件“&#xff0c;即第三方文件&#xff08;库&#xff09;&#xff0c;加入该选项会将文件中包含的子模…

C嘎嘎浅谈模板

这篇文章给大家介绍一下c嘎嘎内存管理和模板&#xff0c;那么我们直接进入正题 c/c的程序内存分布 这里的了解一下即可 new和delete的定义和操作 格式&#xff1a;类型* 对象名 new 类型&#xff1b; 数组(对象)定义格式&#xff1a;类型* 对象名 new 类型[元素个数]&…

NOIP图论 最小生成树——Prim算法(详细图解)

最小生成树的概念 经典题目 prim算法简介 prim算法解析 &#xff08;详细图解&#xff09; 代码实现 代码实战 最小生成树的概念 在一给定的无向图G (V, E) 中&#xff0c;(u, v) 代表连接顶点 u 与顶点 v 的边&#xff0c;而 w(u, v) 代表此的边权重&#xff0c;若存在 …

Kali中docker与docker-compose的配置

权限升级 sudo su 升级为root用户 更新软件 apt-get update安装HTTPS协议和CA证书 apt-get install -y apt-transport-https ca-certificates下载docker apt下载docker apt install docker.io 验证docker安装是否成功 查版本 docker -v 启动docker systemctl start …

QT自定义无边框窗口(可移动控制和窗口大小调整)

QT是一个功能强大的跨平台开发框架&#xff0c;它提供了丰富的界面设计工具和组件。在界面开发中&#xff0c;QT窗口自带的标题栏无法满足我们的需求。我们就需要自定义无边框窗口&#xff0c;包括自定义标题栏和窗口大小调整功能。本文将介绍如何在QT中实现这些功能。 一、简…

Java代码基础算法练习-计算握手次数-2024.07.27

任务描述&#xff1a; 有n(0<n<50)个同学聚会&#xff0c;如果见面时&#xff0c;每个人都要跟其他人握手1次&#xff0c;请计算一共握手多少次? 解决思路&#xff1a; 为了计算在一次聚会上 n 个人相互之间握手的总次数&#xff0c;我们可以采用组合数学的方法。给定 …

【QT】TCP

目录 核心API 示例&#xff1a;服务器和客户端信息互发 服务器代码实现 第一步&#xff1a;创建QTcpServer对象的实例 第二步&#xff1a;绑定信号槽&#xff0c;处理新的连接 第三步&#xff1a;绑定并监听端口号 客户端代码实现 第一步&#xff1a;创建socket对象的实…