c++——类和对象(中)

1.类的六个默认成员函数

在一个空类中真的什么都没有吗,错!在创建类的时候,编译器自动生成六个函数,这六个函数叫默认成员函数。但是,如果我们自己实现六个同名函数(依旧有默认成员函数的特性,只是把编译器的替换成了我们的),这样就不会编译器就不会自己生成函数,而是利用我们写的。

---------------------------------------------------------------------------------------------------------------------------------

1.构造函数

概念:我们经常忘记对一个对象的初始化,这会导致一些未知的问题。构造函数也可以叫做初始化函数,帮助我们对对象初始化。

特性:

1. 函数名与类名相同(规定死的,自己实现时,函数名字也必须是类名)。
2.函数名前不需要写void。
2. 可以有参数,但无返回值(编译器给的没有参数)。
3. 对象实例化时(也就是创建对象时)编译器自动调用对应的构造函数
4. 构造函数可以重载。
你可以定义多个同名的构造函数,只要其参数不同。我们知道默认函数都是自动调用,那如何去传参呢?在创建对象时调用构造函数,所以我们可以在创建时传参,如下:
A()和A(int a,int b)构成函数重载,st1没传参数调用的是前者,st2被创建时传入了参数调用了后者。可以发现,比起A()的固定初始化,A(int a,int b)的初始化显然更好。
但是我们还有一种更好的定义方式:
使用全缺省参数让我们可以传参也可以不传,很好用,但是注意一下:如果使用了全缺省参数就不要留下无参的同名函数,这样如果不给全缺省传参时会和无参同名函数冲突,不知道调用哪个。
5.在对象的生命周期内只调用一次
补充:
我们一般不使用编译器自己生成的构造函数, 为什么要自己实现而不用编译器的呢? 因为编译器生成的构造函数有缺陷

对内置类型数据:没有定义要不要去初始化,有可能处理,也有可能不处理。

对自定义类型数据:会调用这个自定义类型里面编译器生成的默认构造函数去处理这个自定义类型数据。这里有两种情况,一种是我们自己在这个这个自定义类型里定义了不同于编译器生成的构造函数(在这种情况下编译不会生成默认构造函数),而找不到默认构造函数就会报错。第二种是我们没有自己实现构造函数(这时编译器自动生成默认构造函数),调用了默认构造函数之后,对这个自定义类型里的内置类型不处理,遇到自定义类型重复以上步骤,最终自定义类型都是由内置类型组成,所以都是不处理,这样就没意义了,如下:

这里我要强调一下:并非是编译器自动生成的函数才叫做默认构造函数,无参构造函数,全缺省参数构造函数都可以叫做默认构造函数,也就是说,虽然我自定义了构造函数导致编译器没有自动生成构造函数,只要我定义的构造函数是无参,或者全缺省参数,我也不报错(上面说了,只调用默认成员函数,没有就会报错),直接调用我定义的函数去初始化。

换句话说,无参构造函数,全缺省参数构造函数伪装成了默认构造函数。严格来讲,无参构造函数,全缺省参数构造函数,编译器生成函数只能存在一个,否则可能应为传参相同的问题产生歧义

下面是两个栈实现队列的部分代码:首先,创建了xx这个队列时,自动调用了默认构造函数,因为st1和st2是自定义类型,所以转而调用Stack中的构造函数去初始化这两个栈,而栈里面的构造函数是我们自己实现的,但它伪装成了默认构造函数,所以调用了这个函数去初始化st1和st2中的变量,所以有了下面的结果,感觉不错。

---------------------------------------------------------------------------------------------------------------------------------

除了上面这样处理以外c++11还为这个缺陷打上了补丁:

在创建类的时候就可以赋予内置类型初始值,这样我们创建对象时内置类型就有了初始值,相当于初始化了,我们把赋予的值叫做缺省值

注意:如果默认构造函数对内置类型做了相关初始化,就以默认构造函数的初始化为准,这也是为

什么叫缺省值的原因,可用可不用嘛。

---------------------------------------------------------------------------------------------------------------------------------

2.析构函数

概念:我们经常忘记对数据进行销毁,比如销毁开辟的动态内存,析构函数帮助我们销毁数据。

特性:

1. 析构函数名是在类名前加上字符 ~。
2. 无参数无返回值类型。
3. 一个类只能有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。注意:析构
函数不能重载
4. 对象生命周期结束时,C++编译系统系统自动调用析构函数
补充:至于要自己定义还是使用编译器自己生成的析构函数,和构造函数的 补充中所说的一致。
---------------------------------------------------------------------------------------------------------------------------------
关于构造函数和析构函数的一些建议:

1.无论是析构函数还是构造函数,大概只有两种情况不需要自己定义:

1).没有资源需要清理(局部变量会自动销毁,资源是指动态内存等不会销毁的数据)   或   在类里面用了缺省值初始化且没有自定义类型 。

2).内置类型没有资源需要初始化或清理,剩下的自定义类型可以正确初始化或清理(自定义类型里面有自己定义的默认成员函数)比如两个上文中两个栈实现队列就是这种情况。

2.在同一生命周期内,按定义的顺序对类构造,但是析构时顺序和构造相反。

---------------------------------------------------------------------------------------------------------------------------------

3.拷贝构造

概念:拷贝构造是指在创建对象的时候将已有对象的内容拷贝到该对象中。实际上拷贝构造就是构造函数的一个特殊分支,本质上还是初始化。

特性:

1.拷贝构造是构造函数的一种重载形式。所以拷贝构造无返回值。

2.拷贝构造的参数只有一个,且必须是类的类型的引用(用指针也可以,只是相对引用来说比较麻烦),如果直接传值的话会报错因为会引发无穷递归:

想要把d1拷贝给d2,先得把d1拷贝给形参date,然后在用date拷贝d2。而想把d1拷贝给date就得先把d1拷贝给新的形参date,这样一直循环发生无穷递归。

3.拷贝构造的使用方法是在创建对象的同A st2(st1)或者A st2 = st1,其中Stack是类名,st1是要拷贝的对象。如下:

4.若未显式定义,编译器会生成默认的拷贝构造函数。 默认的拷贝构造函数按字节拷贝对象,类似于memcpy,这种拷贝叫做浅拷贝,或者值拷贝。

5.如果对象中有指向一块空间的指针的时候还使用浅拷贝,那这两个指针就会指向同一块空间,这样两个对象就不是独立的了,这不是我们想要的。这时候就要深拷贝,你可以定义一个拷贝构造函数,在里面开创新的空间,然后把里面内容改成和要拷贝的对象里指针所指向空间一样的。

总结:

1.如果对象内没有指向空间的指针,那么不需要自己写拷贝构造函数,使用默认拷贝构造函数即可,如果有的话就自己写一个深拷贝。

2.一般需要写析构函数就需要写拷贝构造函数。

4.赋值运算符重载

1)运算符重载

两个类如何比较?定义一个compare函数?那么大于返回真,还是小于返回真?无论如何这样代码可读性会较低。

c++为了增强代码的可读性引入了运算符重载。运算符重载是具有特殊函数名的函数

对于这个函数有如下规则:

1.函数名为关键字operator加上运算符,如:operator<。

2.函数参数个数与操作符的操作数个数保持一致。且参数中必须有至少一个类类型参数。

3.函数的返回值由运算符决定,比如operator==的返回值是bool,operator+的返回值为int。

4.不能用其他符号链接operator构成函数名,只能用内置运算符。而且,在内置运算符中,.*::?:. ,sizeof也不能用来链接。

5.传参数的顺序和操作数顺序一致

6.编译器的规则是当遇到一个类使用运算符时自动调用运算符重载(这也是为什么可读性会增高)先在类里面找,再到全局中找,找不到报错。如下:

st1>st2比较日期是不是非常直观,比调用个compare函数可读性高不少。实际上st1>st2会被转换成st1.opeartor>(st2),是函数调用。可以直接写成转换后的样子,但是说显式写成这样可读性不高,失去了运算符重载的意义。

这里注意一下,如果把opeartor>定义在类外,需要增加一个参数,而在类里隐式的给opeartor>  传入了this指针,实际上也是两个参数。

2)赋值运算符重载

赋值运算符重载同样拥有以上所有特性,这里是对赋值运算符重载的一些补充:

1. 和其他运算符重载不同,赋值重载必须是成员函数,不能定义在全局。同构造,析构,拷贝函数一样,如果没有在类里实现赋值重载,类中会自动生成默认成员函数(该默认成员函数的行为与拷贝构造类似),这样会和全局函数发生冲突。

2.赋值重载和拷贝构造区分

Date st1 = st2;拷贝构造

st3= st4;赋值重载

简单来说,拷贝构造针对的是刚要创建的对象,赋值重载针对的是两个已存在的对象。

3.赋值重载必须有返回值,因为有连续赋值的情况。有两种返回方式,一种是返回引用。一种是返回拷贝。

总的来说返回引用效率高一点。出了作用域后,如果返回对象的生命周期在对象返回后没有结束,并且没有析构,那就返回引用,除此外返回拷贝(使用已经销毁对象的引用会导致不可预知的错误)。

3)前置++和后置++

前置++和后置++的函数名相同,但是前置++应该返回的是++后的值,而后置++返回++之前的值,他们的实现不同,函数名相同,这就需要函数重载。然而,之前规定了运算符的参数个数与操作数个数一致,所以前置和后置++函数的参数都只有this指针。迫不得已,又规定给后置++的参数中多加一个int来区分这两个函数。

这个int参数不需要使用,仅仅为了区分前置和后置++

4)const修饰成员函数

const Date st1;

st1++;

我们用const修饰了st1,但是调用运算符重载函数时编译器传入的this指针是Date*const类型,导致权限放大,这是编译器不允许的。

所以我们需要把this指针类型改为const Date * const,这样无论st1受不受const限制,权限只可能缩小或不变,不可能放大,这是正确的。

this指针是隐式的,要想修饰它,规定在函数后面加const,如:

int Func()const;//声明

int Func()const //定义

{

}

其实const都是修饰的隐含的this指针

注意:

1.只有成员函数能用const修饰。

2.构造函数和析构函数不能使用const修饰。

3.如果要对this指针指向的对象做改动就不能用const修饰成员函数。

5.取地址操作符重载和取const修饰的对象地址的操作符重载

这两个重载使用编译器生成的默认成员函数即可。

Date* operator&()
{
return this ;
}
const Date* operator&()const  //加const修饰this指针,防止权限放大
{
return this ;
}
以上就是这两个重载的样子。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

内容安全(DPI和DFI解析)

内容安全前言&#xff1a; 防火墙的本质其实就是包过滤&#xff0c;我们通常所说的安全设备&#xff08;如&#xff1a;IPS、IDS、AV、WAF&#xff09;的检测重心是应用层。下一代防火墙基于传统防火墙的拓展能力&#xff0c;就是可以将以上的安全设备模块集成在一起&#xff0…

2024国考行测、申论资料大全,做好备考真的很重要!

1. 国考是什么? 国考,全称国家公务员考试,是选拔国家公务员的重要途径。通过国考,你将有机会进入政府部门,为国家建设贡献力量。 2. 国考难在哪里? 国考之所以难,主要体现在以下几个方面: (1) 竞争激烈 每年国考报名人数都在百万以上,而录取率却不足2%。千军万马过独木桥…

【java-数据结构15-模拟实现栈的方法】

上篇文章中&#xff0c;我们已经手动实现了栈&#xff0c;下面&#xff0c;我们将继续手动实现栈的方法~ 1.在栈中存放元素 1.定义一个usedsize&#xff0c;用来临时存放下标 2.当存放一个元素后&#xff0c;下标加一 3.不要忘记判满 如图 代码如下 判满方法 public boolea…

C++——超简单登录项目

程序入口文件 #include <QtWidgets/QApplication> // 包含登录页面头文件 #include "DlgLogin.h"int main(int argc, char *argv[]) {QApplication a(argc, argv);// 程序入口// 调页面起来//DlgMain w;//w.show();// 换成登录页面DlgLogin w;w.show();return…

高级查询(一)

解决需求&#xff1a;Excel都可以轻松搞定 分组查询原理&#xff1a; 语法&#xff1a; SELECT …<列名> FROM <表名> [WHERE<条件表达式> ] GROUP BY 参与分组的列 可以与 聚合函数作用的列 一块显示 注意 SELECT列表中只能包含&#xff1a; 1、被分…

Linux中如何配置虚拟机网络(NAT方法)

首先我们要在Linux中找到配置文件的路径/etc/sysconfig/network-scripts/&#xff0c;然后找到配置文件的名称ifcfg-xxx&#xff08;如&#xff1a;ifcfg-ens33&#xff09;&#xff0c;然后打开这个文件内 容如下&#xff1a; TYPEEthernet # 指定网卡类型是以太网 BOOTPROT…

gin框架学习笔记(三) ——路由请求与相关参数

参数种类与参数处理 查询参数 在讲解查询参数的定义之前&#xff0c;我们先来看一个例子&#xff0c;当我打开了CSDN&#xff0c;我现在想查看我的博客浏览量&#xff0c;那么我就需要点击我的头像来打开我的个人主页,像下面这样: 我们现在把浏览器的网址取下来&#xff0c;…

分布式版本控制工具git

1 安装Git 在linux上我们建议你用二进制的方式来安装git&#xff0c;可以使用发行版包含的基础软件包管理工具来安装&#xff0c;如果你是 是CentOS或者Fedora的操作系统&#xff0c;可以使用yum命令来安装git&#xff1a; $ sudo yum install git如果你是ubuntu或者是Debian…

YOLOv9独家原创改进: 特征融合创新 | 一种基于内容引导注意力(CGA)的混合融合 | IEEE TIP 2024 浙大

💡💡💡创新点:提出了一种基于内容引导注意力(CGA)的混合融合方案,将编码器部分的低级特征与相应的高级特征有效融合。 💡💡💡在多个数据集实现暴力涨点,适用于小目标,低对比度场景 💡💡💡如何跟YOLOv9结合:将backbone和neck的特征融合,改进结构图如下…

sql实践

1.从excel导入数据 在excel导入数据时要先在数据库中创建对应的数据库表 CREATE TABLE your_table_name (crawl_datetime DATE,url CHAR(255),company_name CHAR(255),company_size CHAR(255),company_type CHAR(255),job_type CHAR(255),job_name CHAR(255),edu CHAR(255),e…

LLM推理入门指南③:剖析模型性能

在本系列文章《LLM推理入门指南①&#xff1a;文本生成的初始化与解码阶段》中&#xff0c;作者对Transformer解码器的文本生成算法进行了高层次概述&#xff0c;着重介绍了两个阶段&#xff1a;提示的处理阶段和逐个生成补全词元的多步生成阶段。在上一篇文章《LLM推理入门指南…

【递归、回溯和剪枝】综合训练<二>

1.组合总和 组合总和 解法一&#xff1a; class Solution { public:vector<vector<int>> ret;vector<int> path;int aim;vector<vector<int>> combinationSum(vector<int>& nums, int target) {aim target;dfs(nums, 0, 0);return …

整合Tess4J图文识别技术

1. OCR图文识别介绍 OCR&#xff08;全称 Optical Character Recognition&#xff0c;直译为光学字符识别&#xff09;用于图片文字识别&#xff0c;例如 提取图片中车牌号等等。 Java中实现OCR的技术方案有&#xff1a; 百度OCR&#xff0c;花米Tesseract-OCR&#xff0c;Go…

文心一言 VS 讯飞星火 VS chatgpt (259)-- 算法导论19.3 2题

二、使用聚合分析来证明 FIB-HEAP-DECREASE-KEY 的 O(1) 摊还时间是每一个操作的平均代价。如果要写代码&#xff0c;请用go语言。 文心一言&#xff1a; FIB-HEAP-DECREASE-KEY 是斐波那契堆&#xff08;Fibonacci Heap&#xff09;操作中的一个&#xff0c;它允许我们减少堆…

【LangChain系列 15】语言模型——LLMs(一)

原文地址&#xff1a;【LangChain系列 15】语言模型——LLMs(一) 本文速读&#xff1a; 异步API 自定义LLM Fake LLM HumanInput LLM 本文将介绍LLMs在LangChain中的一些用法&#xff0c;帮助我们更好地了解LLM模块。 01 异步API LangChain通过异步库实现了对异步的支持&a…

楼宇智慧公厕建设新方案-集成更简单!成本价更低!

在当今的大厦和写字楼中&#xff0c;公厕面临着诸多痛点。 办公楼公厕常常存在厕位难找的问题&#xff0c;使用者不得不花费时间逐一查看&#xff0c;导致效率低下&#xff1b;环境质量也令人担忧&#xff0c;异味、脏污等情况时有发生&#xff0c;影响使用者的心情和健康&…

深入探索Android签名机制:从v1到v3的演进之旅

引言 在Android开发的世界中&#xff0c;APK的签名机制是确保应用安全性的关键环节。随着技术的不断进步&#xff0c;Android签名机制也经历了从v1到v3的演进。本文将带你深入了解Android签名机制的演变过程&#xff0c;揭示每个版本背后的技术细节&#xff0c;并探讨它们对开…

创意无限!AI一键生成漫画视频,每天轻松收入300+,粘贴复制简单操作!

AI项目算是2023到2024一直都非常火爆的项目&#xff0c;这次的AI漫画项目也是相当暴利的项目了&#xff0c;我知道一个老铁通过AI漫画半年已经获利100W了&#xff0c;真的是相当暴利了。 不再多说&#xff0c;直接上手拆解项目。 项目获取&#xff1a; https://zzmbk.com/htt…

linux 任务管理(临时任务定时任务) 实验

目录 任务管理临时任务管理周期任务管理 任务管理 临时任务管理 执行如下命令添加单次任务&#xff0c;输入完成后按组合键Ctrl-D。 [rootopenEuler ~]# at now5min warning: commands will be executed using /bin/sh at> echo "aaa" >> /tmp/at.log at&g…

C++|二叉搜索树

一、二叉搜索树的概念 二叉搜索树又称为二叉排序树&#xff0c;它或者是一颗空树&#xff0c;或者是具有以下性质的二叉树&#xff1a; 若它的左子树不为空&#xff0c;则左子树上所有节点的值小于根节点的值若它的右子树不为空&#xff0c;则右子树上所有节点的值都大于根结…