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.没有资源需要清理   或   在类里面用了缺省值初始化且没有自定义类型 。

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

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

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

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 ;
}
以上就是这两个重载的样子。

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

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

相关文章

Django项目之电商购物商城 -- 创建收货地址

Django项目之电商购物商城 – 创建收货地址 一. 在users中创建新的视图与路由用于创建收货地址 # 设置收货地址 class AddressView(View):def get(self , request):return render(request , "user_center_site.html")# 设置收货地址path(user_center_site/, views.…

金和OAC6 FileDownLoad 任意文件读取漏洞

文章目录 免责声明漏洞描述漏洞原理影响版本漏洞复现修复建议 免责声明 没有网络安全就没有国家安全&#xff0c;该文章只为学习和交流&#xff0c;利用做违法乱纪的事&#xff0c;与本人无关 漏洞描述 金和网络是专业信息化服务商,为城市监管部门提供了互联网监管解决方案,…

AI视频教程下载:零代码创建AI智能体、AI Agents和ChatGPT的Gpts

这门课程专注于提示工程的掌握&#xff0c;教你以精确的方式引导GPT&#xff0c;利用它们的生成能力产生卓越的AI驱动结果。一步一步地&#xff0c;你将学会创建多样化的GPT军团——每个都设计来满足特定的专业需求。 从提供个性化职业变更指导的职业教练AI&#xff0c;到以惊…

IDEA切换分支

方法一 1、选择要切换分支的module 2、右键&#xff0c;选择git 3、再点击branches 4、可以看到当前module的本地分支&#xff08;local Branches&#xff09;及远程分支&#xff08;Remote Branches&#xff09;列表。点击你要切换到的分支,Checkout即可。 方法二 1、点击…

MATLAB模拟退火算法、遗传算法、蚁群算法、粒子群算法

概况 模拟退火算法、遗传算法、蚁群算法、粒子群算法等算法&#xff0c;都是属于概率算法&#xff0c;不绝对&#xff0c;不迅速&#xff0c;能用其它方式解决的问题&#xff0c;不要用这些相对复杂的算法&#xff0c;比如有明确的线性关系或者非线性对应关系。这里的概率算法…

大模型背后的秘密公式: Q*?

这麽说好像我是James Bond后面那个厉害的Q先生&#xff0c;Q是英文Quartermaster&#xff08;軍需官&#xff09;第1個英文字大寫&#xff0c;是007系列英國祕勤局虛構部門Q部門的領導。 Stanford大学的研究者最近发表了一篇名为"From r to Q*: Your Language Model is S…

回答篇:测试开发高频面试题目

引用之前文章&#xff1a;《测试开发高频面试题目》 https://blog.csdn.net/qq_41214208/article/details/138193469?spm1001.2014.3001.5502 本篇文章是回答篇&#xff08;持续更新中&#xff09; 1. 什么是测试开发以及其在软件开发流程中的作用。 a. 测试开发是指测试人员或…

ABC352编程笔记

ABC352 编程笔记 题意&#xff1a;输入&#xff0c;四个数 a , b , c , d a,b,c,d a,b,c,d&#xff0c;若 d d d 在 c , d c,d c,d 之间&#xff0c;则输出 Yes&#xff0c;否则输出 No。 正解&#xff1a;直接判断。 #include <bits/stdc.h> //#define int long lo…

基于 stable diffusion 制作上世纪90年代的游戏美术风格

1. 项目背景 目前游戏项目中出现美术产能不足的瓶颈&#xff0c;如果使用 midjourney 之类的第三方生成式人工智能产品生成美术素材的话&#xff0c;一方面需要将我们的美术资产投喂给第三方企业进行风格训练&#xff0c;有安全性上的风险&#xff0c;另一方面&#xff0c;第三…

华为ensp中BFD和OSPF联动(原理及配置命令)

作者主页&#xff1a;点击&#xff01; ENSP专栏&#xff1a;点击&#xff01; 创作时间&#xff1a;2024年5月6日20点26分 BFD通常指的是双向转发检测。BFD是一个旨在快速检测通信链路故障的网络协议&#xff0c;提供了低开销、短延迟的链路故障检测机制。它主要用于监测两个…

VisualGDB:Linux静态库项目创建、编译及库的使用

接上篇《VisualGDB&#xff1a;Linux动态库项目创建、编译及库的使用》&#xff0c;静态库的创建和使用与动态库基本无差别&#xff0c;唯一需要做的就是指定项目生成静态库。 一、指定项目生成静态库 二、重新构建和编译项目 这里注意&#xff0c;同样要copy一个libxxx.so格式…

【Spring】GoF 之代理模式

一、代理模式 在 Java 程序中的代理模式的作用&#xff1a; 当一个对象需要受到保护的时候&#xff0c;可以考虑使用代理对象去完成某个行为 需要给某个对象的功能进行功能增强的时候&#xff0c;可以考虑找一个代理进行增强 A 对象无法和 B 对象直接交互时&#xff0c;也可以…

IDEA终端环境配置

Idea如何配置终端&#xff1b; 第一步&#xff1a;找到我的电脑&#xff0c;右击——属性——高级系统设置——环境变量 先配置path: 在后面加入&#xff1a;C:\Program Files (x86)\Java\jdk1.7.0_75\bin&#xff08;每个人放置jdk的位置不同。&#xff09; 新建classpath:…

华为OD机试【贪吃的猴子】(java)(200分)

1、题目描述 只贪吃的猴子&#xff0c;来到一个果园&#xff0c;发现许多串香蕉排成一行&#xff0c;每串香蕉上有若干根香蕉。每串香蕉的根数由数组numbers给出。 猴子获取香蕉&#xff0c;每次都只能从行的开头或者末尾获取&#xff0c;并且只能获取N次&#xff0c;求猴子最…

机器人系统ros2-开发实践08-了解如何使用 tf2 来访问坐标帧转换(Python)

tf2 库允许你在 ROS 节点中查询两个帧之间的转换。这个查询可以是阻塞的&#xff0c;也可以是非阻塞的&#xff0c;取决于你的需求。下面是一个基本的 Python 示例&#xff0c;展示如何在 ROS 节点中使用 tf2 查询帧转换。 本教程假设您已完成tf2 静态广播器教程 (Python)和tf…

如何高效解决渠道问题

品牌渠道会围绕销售做一系列活动&#xff0c;定价也会影响渠道的发展&#xff0c;同样的维护好价格&#xff0c;对渠道来说同样重要&#xff0c;渠道中常见的问题包含低价、窜货等&#xff0c;当低价问题不及时解决&#xff0c;会波及影响更多链接&#xff0c;使其他店铺为了流…

力扣刷题第1天:消失的数字

大家好啊&#xff0c;从今天开始将会和大家一起刷题&#xff0c;从今天开始小生也会开辟新的专栏。&#x1f61c;&#x1f61c;&#x1f61c; 目录 第一部分&#xff1a;题目描述 第二部分&#xff1a;题目分析 第三部分&#xff1a;解决方法 3.1 思路一&#xff1a;先排序…

企业短信平台群发_专业群发短信平台

企业平台群发是一种方便、高效的营销方式&#xff0c;通过专业群发平台&#xff0c;企业能够快速、准确地向大量目标客户发送&#xff0c;提高品牌知名度、促进销售和客户互动。下面将详细介绍企业短信平台群发的优势及使用方法。 优势 提高信息覆盖率 企业平台群发可以让企业…

html--瀑布效果

<!doctype html> <html> <head> <meta charset"utf-8"> <title>瀑布效果</title><style> body {background: #222;color: white;overflow:hidden; }#container {box-shadow: inset 0 1px 0 #444, 0 -1px 0 #000;height: 1…

Vue 插槽

Vue插槽是一种特殊的语法&#xff0c;用于在组件中定义可复用的模板部分。它允许开发者在组件的标记中声明一个或多个插槽&#xff0c;然后在使用该组件时&#xff0c;可以根据自己的需求将内容插入到这些插槽中。 Vue插槽分为默认插槽和具名插槽两种。 目录 默认插槽 语法…