做任务挣钱的网站app,红色餐饮网站源码,新手建设html5网站,wordpress 获取分类子分类前言#xff1a; 上一篇小编讲了类和对象#xff08;1#xff09;#xff0c;当然#xff0c;在看这篇文章之前#xff0c;读者朋友们一定要掌握好前面的基础内容#xff0c;因为这篇和前面息息相关#xff0c;废话不多说#xff0c;下面小编就加快步伐#xff0c;开…前言 上一篇小编讲了类和对象1当然在看这篇文章之前读者朋友们一定要掌握好前面的基础内容因为这篇和前面息息相关废话不多说下面小编就加快步伐开始今天这篇文章的讲解。 目录 1.类的默认成员函数 2.构造函数 2.1.构造函数的概念 2.2.构造函数的特点 2.1.1.前四个特点 2.1.2.后三个特点 3.析构函数 3.1.析构函数的概念 3.2.析构函数的特点 3.2.1.前四个特点 3.2.2.后四个特点 4.拷贝构造函数 4.1.拷贝构造函数的概念 4.2.拷贝构造函数的特点 4.2.1.前三个特点 4.2.2.后三个特点 5.赋值运算符重载 5.1.运算符重载 5.1.1.运算符重载前几个特点 . 5.1.2.运算符重载的后几个特点编辑 5.2.赋值运算符重载的书写 6.取地址运算符重载 6.1.const成员函数 6.2.取地址运算符重载 7.总结 正文
1.类的默认成员函数 默认成员函数就是用户没有显示实现大白话来讲就是没有写相关的函数编译器自动生成的成员函数就被称之为默认成员函数。一个类在我们不写的时候编译器会形成一下六个默认成员函数 不过值得注意的是这6个成员函数中前四个是比较重要的小编今天首先是要讲完这四个函数至于后两个小编准备在下一篇在讲不过最后两个理解一下就好目前我们不需要太多了解前四个是我们要知道的这对于我们以后的学习有很大的意义C11以后还会增加两个成员函数这两个成员函数小编还没学到所以先放一放。默认成员函数是一个很重要的概念但是也是很复杂的我们需要从以下两个方面去了解 我们已经了解了默认成员函数是什么了下面我们开始深层次的进入讲解下面登场的是构造函数 2.构造函数 2.1.构造函数的概念 可能会多读者朋友看到这个函数的名字会自己认为这个函数就是来开空间创造对象的那可就大错特错了构造函数是对象进行实例化以后对对象进行初始化的。小编之前也写过栈和队列这两种数据结构在当时小编就写了初始化函数Init而构造函数的本质就是用来替代栈和队列的Init函数的因为当我们写完构造函数以后编译器是会自动调用构造函数的所以构造函数是可以完美替代Init函数的这便是构造函数的概念当我们了解完概念以后下面就要开始进入构造函数的特点讲解了 2.2.构造函数的特点 2.1.1.前四个特点 小编先从这四个方面进行讲解先从第一点进行讲解对于这个特点就是我们在写构造函数的时候的函数名是和类的名字是一样的对于它的返回点第二个特点已经告诉我们了它是不需要有返回值的下面小编就就简单的写一个日期类的构造函数来帮助各位读者朋友进行了解
using namespace std;class date
{
public:date() //构造函数是可以重载的参数可以带也可以不带后面会说{_year 2024;_month 8;_day 13;}
private:int _year;int _month;int _day;
}; 通过上面的代码可以帮组各位读者朋友了解构造函数的写法这只是构造函数的一种小编在代码里也说过构造函数的形参可以有也可以没有因为第四个特点就说明了构造函数是可以重载的所以构造函数我们在书写的时候有时候带参有时候不带参数但是小编推荐各位读者朋友可以写一个全缺省的构造函数因为这样比较方便。我们已经讲述了构造函数的三个特点接下来就是第三个特点还没有说其实小编在之前也提过一嘴对于构造函数我们在实例化对象以后编译器是会自动调用的下面小编展示一下如何使用构造函数
using namespace std;class date
{
public:date(int year 2024,int month 8,int day 13) //构造函数是可以重载的参数可以带也可以不带后面会说{_year 2024;_month 8;_day 13;}
private:int _year;int _month;int _day;
};
int main()
{date s1(2024,8,14); //对于全缺省的构造函数的调用我们仅需在对象后直接用括号然后放入我们想要的实参就好了或者我们不需要这么写。date s2; //对于全缺省的或者不带参的也可以这么写return 0;
} 对于构造函数的使用正如小编上面的代码图一样此时我们可以分为两种情况一种是必须要写实参的那个时候就是我们把上面代码的缺省值给全去掉此时我们就必须要写实参了还有一种就是不带参数或者全缺省的此时不带参的我们不写实参而全缺省的我们可以不用写实参当然也可以写但一般我们都会写的小编在之后讲完整时间类的时候就推荐各位去写。此时就是构造函数的前四个特点前四个特点还是比较容易理解的各位一定要好好的知道并且理解这些特点下面我们开始讲述后三个特点。 2.1.2.后三个特点 先看第五个特点它告诉了我们如果我们不写构造函数的话系统是会帮助我们生成一个默认构造函数这个特点应该搭配着第七个特点进行查看对于我们不写系统默认生成的构造对于内置类型的构造是不确定的可能很多读者朋友不知道内置类型是什么意思小编在这里简单的说一下内置类型是编译器默认安置一些简单的类型就比如整型浮点型等等这些都是内置类型而内置类型如果不写构造函数的话对于它是否可以进行初始化这个是要看编译器的下面小编用VS2022的编译器来带着大家去看一看如果我们对于内置类型的类不写构造会怎么样 如上图所示此时编译器实际上并没有给我们进行初始化所以上面说过内置类型系统给我们的构造函数是要看编译器的如果不给我们初始化那也是很正常的所以我们要有自己写初始化奇函数的习惯这个在之后的学习生活都是很重要的我们继续接着第七点进行看对于自定义类型的成员编译器会默认去调用它自己的构造函数如果没有的话是会报错的可能很多读者朋友不知道自定义类型有什么小编也说说自定义类型就是一些复杂的类型比如结构体类这些都是我们去自己定义的类型所以是自定义类型对于自定义类型的成员的书写小编在之前写过队列的习题中我们用两个栈实现一个队列的时候MyQueue成员函数就是两个自定义类型这时候我们是不需要写构造函数的此时这俩自定义是会自己调用自己的构造函数的只不过我们需要去写它们各自的构造函数的罢了下面小编来讲一下我没讲的最后一个特点也就是第六个特点 第六个特点告诉我们默认构造函数的相关概念很多读者朋友看到这个名字可能就是觉得系统默认给我们的构造函数就是默认构造函数其实这是默认构造函数的一种默认构造函数还有无参的构造全缺省的构造这三个类型的默认构造函数我们在写的时候只能出现一次不能同时存在如果我们不写构造函数那就代表第一种编译器默认给的构造函数存在如果我们写了无参的默认构造那么全缺省我们不能在写虽然在语法上这样是可以的但是会产生歧义因为如果我们不写实参编译器不知道会调用哪一个函数所以说这三种类型只能出现其中一个我们在写构造函数的时候一般也就写默认构造函数小编还是推荐各位读者朋友用全缺省的默认构造函数这样比较省心点。 此时小编已经讲述了构造函数的全部特点了那么现在我们加快脚步开始进入下一个函数析构函数的讲解 3.析构函数 3.1.析构函数的概念 析构函数这个名字相信很多读者朋友看到这个名字的第一印象就是把对象给销毁的函数小编当时也是这么想的但其实它的作用是和构造函数相反的析构函数是用来对对象中的资源进行释放的这些资源就比如我们在写栈的时候我们动态内存开辟的空间文件操作时产生的资源等等这便是析构函数的作用可以把它看作是它是来替代我们以前写过的销毁函数的另外小编在说一下对于对象的销毁我们在设置对象的时候把对象放在了函数这个栈帧中当我们出去函数栈帧的时候编译器就会帮助我们把对象给销毁了所以我们无须在自己销毁对象了这是编译器给予我们的便利性以上就是析构函数的概念下面小编来讲述一下析构函数的特点。 3.2.析构函数的特点 3.2.1.前四个特点 先从第一点第二点来看析构函数的命名特点和前面的构造函数是有一点类似的 它们都是不需要返回值的只不过对于函数的命名析构函数比构造函数多了个~这个符号在C语言中有按位取反的意思我们记析构函数的时候也可以这么记因为正好析构函数和构造函数两个函数的功能是相反的所以我们用~也是正常的我们继续看第二个特点析构函数是没有参数的自然不会在有函数重载从而可以比较好理解第三个特点一个类只允许有一个析构函数因为析构函数无参不可以函数重载下面小编先写个析构函数来帮助读者朋友知道我们如何使用析构函数
//一般来说内置类型我们不需要析构函数的因为内置类型没有用到资源所以小编就拿之前讲过的栈举例子因为栈动态开辟了空间
class Strack
{
public:Strack(int n 4){arr (int*)malloc(sizeof(int) * n);capciaty n;top 0;cout Strack() endl;}~Strack(){free(arr);arr NULL;capciaty top 0;cout ~Strack() endl; //这里使用打印是为了后续自定义类型的成员默认去调用自己的析构函数帮助各位读者朋友去理解的}
private:int top; //栈顶元素int capciaty; //总空间大小int* arr;
}; 上面就是构造函数和析构函数的书写小编在概念的时候也说过析构函数就是来完美替代销毁函数的它的书写和销毁函数是类似的不过我们在写销毁函数的时候我们还需要去调用函数但是析构函数是不需要我们手动调用的第四个特点说了在我们写的主函数生命周期结束以后析构函数是会去自动调用的所以说我们只要写完了析构函数以后我们就无需在主函数中去使用它编译器会帮助我们去自动调用这个函数的所以这么做可以帮助那些常忘记写销毁函数的读者朋友这也是C对于C的增强以上就是前四个特点下面小编来讲述剩下的几个特点
3.2.2.后四个特点 先从头开始看起析构函数和构造函数的相似之处是有很多的我们不写析构函数的时候对于内置类型的成员不用处理对于自定义类型的成员就需要去调用它自己的析构函数对于自定义类型的成员小编这里就写个双栈实现队列的数据结构来帮助读者朋友去理解它们的析构函数是会自己调用的。
class MyQueue
{
private:Strack s1;Strack s2;
};int main()
{MyQueue a1;return 0;
} 通过打印结果我们可以清晰的看出此时编译器自动帮我们去调用了自定义类型的析构函数和构造函数所以对于自定义类型的成员我们无须去自己写构造函数当然我们也可以写但是写的话会显的代码很赘余我们写代码自然是越简洁越好太长了的话后续我们找错误的代码的时候会很累的此时印证了第六个特点自定义类型是会自己去调用自己的析构函数的我们再看第七个特点对于一些不需要去申请资源的类我们就不需要写析构函数就比如小编之前写过的简易时间类这个类就不需要去写析构函数因为它的成员变量都没涉及到一些资源当然小编上面写的代码对于只有自定义类型成员的类我们也不需要写析构函数因为它会去自动调用各自的析构函数对于小编写过的Strack类这个栈因为涉及到了动态内存的使用也就是资源的使用所以我们就必须要写析构函数编译器是不会对这些动态开辟的空间进行自主释放的。接下来就是最后一个特点这个特点也说的很清晰明了对于类里面涉及到的多个对象最后定义的成员是会先析构的这个特点搭配着调试功能会更好看出来各位读者朋友记住这个功能就好之后小编在讲解一些题目的时候可能会涉及到下面我们进入第三个默认成员函数——拷贝构造函数。 4.拷贝构造函数
4.1.拷贝构造函数的概念 如果一个函数的第一个参数是自身类类型的引用且任何额外的参数都有默认值则此构造函数也叫做拷贝构造函数也就是说拷贝构造函数是一个比较特殊的构造函数。简单来说拷贝构造函数就是把一个类类型的对象赋值给一个刚创建的对象类似下面这样
A a; //此时就默认已经调用构造函数了
A d a;
4.2.拷贝构造函数的特点 4.2.1.前三个特点 1.拷贝构造函数是构造函数的重载。对于这句话可能一些读者朋友看着会懵因为各位还不知道拷贝构造函数如何去写等会小编会结合第二个特点来说写法的各位可以先知道拷贝构造函数是构造函数的重载就行~ 2.拷贝构造函数第一个参数必须是类类型对象的引用使用传值的方式编译器会直接进行报错的因为语法逻辑上会造成无线递归这个特点小编等会会告诉各位这是为何的拷贝构造函数也可以有多个参数但是第一个参数一定是类类型对象的引用后面的参数必须有缺省值。对于这个特点小编有话说首先我们从开头开始看此时这个特点告诉我们拷贝构造函数第一个参数是类类型对象的引用结合第一个特点拷贝构造函数是构造函数的重载这里我们就可以大致推断出拷贝构造函数是如何去写的此时我们还是不用去写返回类型这个重点这篇文章小编隔了半个月重新去写我重新练习这部分内容的时候我就忘记了拷贝构造函数是没有返回值的直到我写了这篇文章才反应过来函数名就是类的名字括号里面是一个类类型对象的引用下面小编就书写拷贝构造函数
using namespace std;class A
{
public:A(int time 2024){_time time;}A(const A x) //加const是为了防止权限放大权限可以平等也可以去放大{_time x._time; //把x的内容复制给*this就好}
private:int _time;
}; 上面就是我们日常书写的拷贝构造函数各位读者朋友要培养这么写拷贝构造函数以后我们有很多地方需要用到拷贝构造函数之后我们再往后看后面这句话告诉我们我们在书写拷贝构造函数的时候一定要传引用而不是去直接传类类型的对象对于这个原因小编就从这里开始进行解释这里就牵扯到了下一个特点当我们在调用类类型对象的时候会先进行一次拷贝构造以后在传过去这个点各位读者朋友一定要记住对于为什么这样做小编也不是很清楚理直气壮这涉及到了深拷贝和浅拷贝以后小编了解多了以后会在进行补充所以这个点就说明了为什么我们要传引用如果直接传类类型的时候会先去进行一次拷贝构造如果我们不写出这个拷贝构造的话那么会一直循环去找拷贝构造从而造成死循环这就是为什么会在语法逻辑上无限递归。继续往后面的特点看他告诉我们在括号里面还可以写除了类类型引用外其他的东西这个知道就好一般我们写拷贝构造函数的时候我们仅仅写类类型引用即可这便是拷贝构造函数第二个特点下面我们继续看第三个特点 3.C规定自定义类型对象进行拷贝行为必须调用拷贝构造所以这里自定义类型传值传参和传值返回都会去调用拷贝构造。这个特点小编在上面就已经说了所以就不多赘述了这是拷贝构造函数的前三个特点下面我们进行后三个特点的讲述。 4.2.2.后三个特点 1.若未显示定义拷贝构造编译器会自动生成拷贝构造函数。自动生成的拷贝构造对内置类型成员变量会完成浅拷贝一个字节一个字节的进行拷贝对自定义类型的成员变量会调用它的拷贝构造函数。和前面两个默认成员函数一样拷贝构造我们不写编译器也会去自己生成一个拷贝构造函数这时候可能有很多读者朋友会说了这不是一件好事吗如果这么想那就是大错特错了因为此时系统给我们生成的拷贝构造函数是进行浅拷贝可能很多读者朋友不知道什么叫做浅拷贝这里小编给出解释此时如果我们设置了一个成员变量_a实例化一个对象a我们把a的_a浅拷贝给实例化后的b的_a此时我们需要把a的地址一个字节一个字节的拷贝给b类似于下图这样 上图就展示了如果我们不写拷贝构造函数的话仅仅使用浅拷贝会发生的事情如果我们动态开辟一块空间实例化多个对象如果一个对象进行了释放操作那么经过它拷贝构造出来的所有对象就会全部释放这样的话我们这个类就没有什么意义了所以此时我们就要通过写拷贝构造函数经过深拷贝深拷贝不再是一个字节一个字节的进行拷贝而是会先开辟出一块空间然后把a这个对象的值复制到新建立的空间中就如下图所示 这样我们就可以很好的去实现了真正意义上的拷贝之后我们往后看可以知道拷贝构造函数对待类类型的成员变量的时候也还是会进行调用它们各自的拷贝构造函数这就是第四个特点接下来我们继续往后走 5.由于第五个特点篇幅很长所以我索性就给一个图片了 这个特点是想告诉我们什么时候再去写拷贝构造函数拷贝构造函数并非是一定要写的如我们之前写的时间类这个类的成员就没有涉及到动态内存开辟等等利用资源的方式所以我们就无须在写拷贝构造函数我们通过简单的浅拷贝便可以达到我们的目的深拷贝是对那些申请资源的类有要求一般申请资源的话就必须去写拷贝构造函数当然这个特点也告诉我们如何去判断是否写拷贝构造函数当这个类必须写析构函数的时候并且涉及到了释放资源的过程那么拷贝构造函数是我们一定要去写的这就是第五个特点虽然很长但理解起来还是比较简单的~ 6.特单比较长我就直接图片代文字饿了 这个特点各位读者朋友记住就好小编感觉这个解释就已经很详细了并且如果我没有记错的话我在上一篇文章或者上上篇文章就说明了野引用问题各位读者朋友应该尽量避免野引用的出现以上便就是拷贝构造函数的特点下面我们进入下一个默认成员函数——赋值运算符的重载。 5.赋值运算符重载
5.1.运算符重载 再讲解赋值运算符之前小编先讲述一下什么叫做运算符重载简单来说运算符重载就是让我们可以用类做加减乘除比大小等等一系列功能 等会我们讲述的赋值运算符就是其中的一种下面小编先给各位展示运算符重载的几个特点 5.1.1.运算符重载前几个特点 从头开始看开头就告诉我们想要将运算符用于类类型对象的时候就必须去通过运算符重载的形式去进行定义我们在进行类类型对象的加减的时候此时我们就默认的去调用了相应的运算符重载不然是会报错的我们再看第二个点第二个点告诉了我们如何书写一个运算符重载特点已经讲述的比较详细了小编等会写一个代码来帮助各位读者朋友去了解我们继续往后看第三个特点告诉我们如何去写一个运算符重载这是由运算符作用的对象来决定的就比如我们想写大于等于等等比较类型的运算符那么我们就需要有两个参数如果我们想去写三目运算符那我们就要有三个参数但是三目操作符是不可以重载的后面特点会说等等这就是这个特点要讲的下面我们继续往后看它说明了如果我们把操作符重载作为类成员函数此时我们参数就可以少写一个因为我们都知道类里面的成员函数都有一个隐藏的this指针所以参数可以少写一个并且我们如果书写了很多的运算符重载应该大多数都是类的成员函数不然我们是用不了类的成员变量的一般成员变量都是私有的当然可以有很多办法可以解决这个问题这都是后话了但小编认为还是自己的成员函数放心最后一个特点各位读者朋友记住就好下面我们继续后几个特点的讲述在讲述之前小编先给各位读者朋友展示一个大于操作符的重载
class Time
{
public:Time(int time 122){_time time;}bool operator(Time x){return _time x._time;}
private:int _time;
};
. 5.1.2.运算符重载的后几个特点 先看第一个这个特点是很通俗易懂的我们运算符重载肯定是重载有意义的运算符而不是自己造个新运算符不然不如叫运算符构造得了~各位读者朋友记住这个特点就好下面一个特点就解释了小编讲述运算符重载函数参数的时候为什么说我们不可以重载三目操作符因为C规定了我们不可以去重载至于原因大家不必深究直到不能用就好在以后我们不断的学习中可能就知道祖师爷为什么不让我们去重载这个了之后的几个特点读者朋友看着就能理解小编就不在多叙述了等小编讲述时间类的时候就会对其中几个多做说明下面我们就先重载一个运算符赋值运算符~ 5.2.赋值运算符重载的书写 首先我们在写运算符重载的时候我们需要注意返回类型由于此时我们是赋值运算符重载所以返回的类型肯定就是类类型此时我们在返回的时候可以传引用返回减少临时空间的产生增加代码的效率此时我们是需要把赋值运算符重载作为类成员函数的所以此时我们仅需写一个形参即可赋值操作涉及到了两个类的操作所以我们直接传一个类类型对象的引用即可这样可以减少拷贝构造函数的生成之后的操作其实就和我们之前写的拷贝构造函数一样了有些读者朋友可能会分不清拷贝构造函数和赋值运算符两个的区别他俩的区别是很容易判别出来的拷贝构造函数是把一个存在的类对象的内容深拷贝给一个刚刚建立的对象而赋值运算符重载则是针对于两个已经存在于类对象这两个函数针对的两个作用对象是不同的所以这就是他们的区别下面小编就给各位展示一下赋值运算符重载函数的写法
class Date
{Date(int year 2024, int month 9, int day 17){_year year;_month month;_day day;}Date(Date x){_year x._day;_month x._month;_day x._day;}Date operator(Date x){_year x._year;_month x._month;_day x._day;}
private:int _year;int _month;int _day;
}; 下面我们进入下一个函数的讲解~ 6.取地址运算符重载
6.1.const成员函数 const成员函数是我们学习的第五个成员函数这个成员函数重要程度和前几个相比就很小了但我们还是要去了解的此时const引用其实就是去限制我们的this指针的可能很多读者朋友很好奇它的作用是什么看看小编下面的代码就知道是什么意思了
class wang
{
public:wang(int time 102){_time time;}wang(wang s1){_time s1._time;}void Print(){cout _time endl;}
private:int _time;
};int main()
{const wang s1;s1.Print();return 0;
} 猜一猜上面的代码是否可以运行很显然这个代码是不可以去运行的报错原因如下图所示 此时我们设置的类类型对象s1是const类型所以我们在使用函数的时候如果我们不传const类型的引用那么会出现一种情况变量自身是无法被改变的但是变量的小名却是可以被改变的这样是不符合常理的所以再给函数传变量的时候我们需要去传const类型的引用从而避免权利放大的问题关于权利放大的问题小编在之前文章也说过权利是可以平等或者缩小的但是不可以出现权利放大的问题所以如果我们想要让this指针收到const限制我们仅需在函数后面加上const即可如下面代码所示
using namespace std;class wang
{
public:wang(int time 12){_time time;}void Print()const{cout _time endl;}
private:int _time;
};int main()
{const wang a; //consta.Print();return 0;
} 上面小编就展示了const是如何在成员函数中使用的我们仅需在括号后面加上const即可这便是const成员函数的用法这个是比较容易理解的并且重要程度比较低的各位读者朋友知道它的概念和怎么用即可下面我们进入最后一个默认成员函数的讲解——取地址运算符重载。
6.2.取地址运算符重载 取地址运算符重载分为普通取地址运算符重载以及const取地址运算符重载一般这两个运算符编译器是会帮助我们自主去生成的我们直接使用编译器给我们的即可不需要自己去实现除非一种特殊情况的发生就比如你和小王两个人共同去完成一个项目有一天你两个突然吵架了此时你很像搞小王一下于是自己写了取地址运算符重载让小王在使用取地址操作符的时候取不到类的地址从而做到了恶搞的目的当然这是小编不提倡的这样可能会让这个项目直接黄了所以我们一般在这种情境下去进行取地址运算符的重载下面小编就给出取地址运算符重载的书写方式其实就是套用了运算符重载的知识
class wang
{
public:wang(int time 12){_time time;}void Print()const{cout _time endl;}const wang* operator(){return (wang*)0x11222131;//这是恶搞别人的版本return this; //正经版本}
private:int _time;
}; 7.总结 这篇文章到这也是写完了有一说一小编这篇文章本来应该很早就写完的但是暑假末期我开摆了于是我拖到现在才写完这里我得批评下自己太懒了所以这篇文章跨越的时间有点长所以可能会出现有一些语言的不搭希望各位读者朋友理解如果文章有错误的话可以在评论区指出小编会及时的回复那么我们下一篇文章见啦