【C++】类与对象的学习(中)

目录

一、默认成员函数:

二、构造函数:

1、定义:

2、理解:

三、析构函数:

1、定义:

2、理解:

四、拷贝构造:

1、定义:

2、理解:

五、运算符的重载:

1、一般运算符的重载:

2、赋值运算符的重载:

1、格式:

2、注意:


一、默认成员函数:

一个类中,里面什么都不写的话就叫做空类,但在其中并不是什么都没有的,编译器会自动生成6个默认成员函数。

默认成员函数:用户没有显式实现,编译器会生成的成员函数称为默认成员函数。

二、构造函数:

1、定义:

构造函数是一个特殊的成员函数,它的名字必须和类名相同,创建类类型对象时,由编译器自动调用,,以保证每个数据成员都有 一个合适的初始值,并且在对象整个生命周期内只调用一次。

这是每次创建一个实例时,这个函数都会调用一次。

2、理解:

1、函数名与类名相同。

2、无返回值(也不用写void)。

3、对象实例化的时候,编译器自动调用对应的构造函数。

接下来用一串代码理解上述3条特征。

class Date
{
public:Date(){_year = 2;_month = 2;_day = 2;}void Print(){cout << _year << "-" << _month << "-" << _day << endl;}
private:int _year;int _month;int _day;
};
int main()
{Date d1;d1.Print();return 0;
}

上述代码中,Date()这个就是一个构造函数,和类名相同,也不用写任何返回值,可以看到运行后的结果是已经调用构造函数Date后的值

4、函数构造可以进行重载。

注意:无参构造函数的调用后面不加(),这样和函数的声明会产生歧义。

class Date
{
public:Date(){cout << "无参数构造函数的调用" << endl;_year = 2;_month = 2;_day = 2;}Date(int year, int month, int day){cout << "有三个参数构造函数的调用" << endl;_year = year;_month = month;_day = day;}void Print(){cout << _year << "-" << _month << "-" << _day << endl;}
private:int _year;int _month;int _day;
};
int main()
{Date d1;//调用无参构造函数d1.Print();Date d2(2024,7,4);//调用带参数的构造函数d2.Print();return 0;
}

5、如果类中没有显式定义构造函数,那么C++编译器会自动生成一个无参的默认构造函数,一旦用户显式定义编译器将不再生成。

6、首先要知道:

C++把类型分为了两种:

a、内置类型(基本类型):int/char/double...

b、自定义类型:struct/class/union...

如果我们不写构造函数,那么编译器就会默认生成构造函数,此时这个默认构造函数会对内置类型不做任何处理(虽然有些编译器会进行处理,但那是个性化的,不是所有的编译器都会处理),自定义类型就会去调用它的默认构造。

class Date
{
public:Date(){cout << "无参数构造函数的调用by Date" << endl;_year = 2;_month = 2;_day = 2;}Date(int year, int month, int day){cout << "有三个参数构造函数的调用by Date" << endl;_year = year;_month = month;_day = day;}void Print(){cout << _year << "-" << _month << "-" << _day << endl;}
private:int _year;int _month;int _day;
};class Stu
{
private:char name[20];int age;char id[15];Date d1;
};int main()
{Stu s1;return 0;
}

如上所示:

实例化Stu这个类,但是发现没有写构造函数,就会默认生成个构造函数,那些内置类型不做处理,自定义类型d1就会调用它的默认构造(Date())。

如下图都是内置类型,就不会做任何处理。

7、无参的构造函数和全缺省的构造函数都称为默认构造函数,并且默认构造函数只能有一个

理解:不传参就可以调用的是默认构造函数
注意:无参构造函数、全缺省构造函数、我们没写编译器默认生成的构造函数,都可以认为
是默认构造函数。

所以:

1、一般情况下,有内置类型成员,就需要自己写构造函数,不能用编译器自己生成。

2、如果全部都是自定义类型的成员,那么就可以考虑使用编译器自己生成的构造函数。

ps:

在C++11中,在成员变量声明的时候可以给缺省值。

如上所示:

在Date这个类中,可以给默认缺省值,给编译器生成默认构造函数用。

注意:

C++11以后才支持的,这里是进行声明(因为没有创建空间),不是初始化!!!

对于构造函数:
一般情况下都需要自己写,

但是,下面两种情况可以不用自己写:

a、内置成员都有缺省值,且初始化符合我们的要求。

b、全是自定义类型的构造,且这些类型都定义默认构造。

三、析构函数:

1、定义:

析构函数与构造函数功能相反,析构函数不是完成对对象本身的销毁,局部对象销毁工作是由编译器完成的。而对象销毁时会自动调用析构函数,完成对象中资源的清理工作。

2、理解:

1、析构函数名就是类名前面加上一个“~”;

2、和构造函数一样没有参数返回类型,并且没有参数,所以不能够重载

3、 一个类只能有一个析构函数。若未显式定义,系统会自动生成默认的析构函数,在程序结束的时候自动调用;

4、自动生成的默认析构函数,对内置类型不做处理,自定义类型会调用其析构函数。

那么什么时候可以显示定义析构函数,什么时候可以不用显示定义析构函数呢:

1、一般,当存在动态申请资源的时候就需要显示定义;

2、当没有动态申请资源的时候就不用显示定义;

3、当需要释放资源的成员变量都是自定义类型的时候,不用写析构,这个自定义类型就会调用它的析构函数。

#include<iostream>
using std::cout;
using std::endl;class Stack
{
public:Stack(){cout << "Stack()已经调用" << endl;_a = (int*)malloc(sizeof(int) * 4);if (_a == nullptr){perror("stack malloc fail");return;}_capacity = 4;_top = 0;}Stack(int capacity){cout << "Stack(int capacity)已经调用" << endl;_a = (int*)malloc(sizeof(int) * capacity);if (_a == nullptr){perror("stack malloc fail");return;}_capacity = capacity;_top = 0;}~Stack(){cout << "~Stack()已经调用" << endl;free(_a);_a = nullptr;_capacity = _top = 0;}
private:int* _a =  nullptr;int _top = 0;int _capacity;
};int main()
{Stack s1;Stack s2(10);return 0;
}

如上~Stack()就是一个析构函数,当对象销毁时就会自动调用。

四、拷贝构造:

首先要了解:C++规定,传参赋值中:创建一个已有对象一模一样的新对象,内置类型直接拷贝,传值的自定义类型必须调用拷贝构造完成拷贝(深浅拷贝有关系)

1、定义:

首先要了解到,拷贝引入是在创建对象的时候,创建一个已有对象一模一样的新对象。

它只有一个形参,该形参是我要复制的对象(一般可以用const修饰),在用已存在的类类型对象创建新对象时由编译器自动调用。

2、理解:

1、拷贝构造是构造函数的一种重载形式;

2、拷贝构造函数的参数只有一个且必须是类类型对象的引用,使用传值方式编译器直接报错,因为会引发无穷递归调用。

3、当没有显示定义拷贝构造函数的时候,默认拷贝构造会对内置类型成员完成值拷贝

                                                                           对自定义类型成员会调用它的拷贝构造

此时在日期类中,可以不用写默认拷贝拷贝构造,正常拷贝,但是有些情况,比如在栈这个类中,如果使用编译器给的默认拷贝构造,会存在问题,会拷贝出同一个指向同一空间的指针,这时如果析构的话,会对同一块空间释放两次,这时程序就会崩溃了。

针对上述为题,我们就需要自己实现拷贝构造,实现深拷贝来解决上述问题。

就要完成开辟一块空间,然后在这块空间里面,拷贝那些值。

class Date
{
public:Date(int year = 2000, int month = 1, int day = 1){_year = year;_month = month;_day = day;}Date(const Date& d){_year = d._year;_month = d._month;_day = d._day;}
private:int _year;int _month;int _day;
};int main()
{Date d1(2024, 7, 13);Date d2(d1);return 0;
}

上述就是浅拷贝的例子。

接下来,对这个栈实现深拷贝:

	Stack(Stack& st){_a = (int*)malloc(sizeof(int) * st._capacity);if (_a == nullptr){perror("stack malloc fail");return;}memcpy(_a, st._a, sizeof(int) * st._capacity);_top = st._top;_capacity = st._capacity;}

五、运算符的重载:

1、一般运算符的重载:

C++相对于C语言,增加了运算符重载。使用关键字operator后面加上要重载的运算符。

函数名:operator<

函数原型:返回值类型 operator操作符(参数列表)

注意:

1、不能通过连接其他符号来创建新的操作符:比如operator@(原来没有@这个操作符)
2、重载操作符必须有一个自定义型参数,不能都是内置类型,毕竟是比较自定义类型的,可以自定义类型和内置类型同时存在。    
3、用于内置类型的运算符,其含义不能改变,例如:内置的整型+,不能改变其含义
4、作为类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐藏的this
5、    .*    ::     sizeof     ?:     .     注意以上5个运算符不能重载。

bool operator<(const Date& x)
{if (_year > x._year){return false;}else if (_year == x._year && _year > x._year){return false;}else if (_year == x._year && _year > x._year && _day > x._day){return false;}return true;
}

以上就是重载<运算符,_year实际上是this->_year,但是如果写在全局域中,那么就会无法访问私有成员,解决办法可以用友元,或者把operator<写成成员函数。

2、赋值运算符的重载:

1、格式:

1、参数类型:const 类名&,传递引用可以提高传参效率
2、返回值类型:类名&,返回引用可以提高返回的效率,有返回值目的是为了支持连续赋值
3、返回*this :要复合连续赋值的含义

2、注意:

赋值运算符只能重载成类的成员函数不能重载成全局函数,因为赋值运算符如果不显式实现,编译器会生成一个默认的。此时用户再在类外自己实现一个全局的赋值运算符重载,就和编译器在类中生成的默认赋值运算符重载冲突了,故赋值运算符重载只能是类的成员函数。

在这默认生成赋值重载和拷贝构造行为一样,

对内置类型成员进行值拷贝/浅拷贝,

对自定义类型成员会调用它的赋值重载。

Date& operator=(const Date& d)
{if (this != &d){_year = d._year;_month = d._month;_day = d._day;}return (*this);
}

以上就是在日期类的重载赋值符,这个与拷贝构造不一样,拷贝构造是通过一个类创造一个一样的类,而这个是将一个已经存在的类赋值给另一个已经存在的类。

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

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

相关文章

夏令营入门组day5

目录 一. 城市距离 二. 史莱姆 一. 城市距离 &#xff08;1&#xff09;思路 每次询问&#xff0c;对于每一个点都判断与下一个点是否为临近点会超时&#xff0c;因此预处理&#xff0c;预先判断每一个点的临近点&#xff0c;然后将花费存入前缀和数组&#xff0c;这样在每次询…

对redis进行深入学习

目录 1. 什么是redis&#xff1f;1.1 为什么使用redis作为缓存&#xff1f;1.1.0 数据库&#xff08;MySQL&#xff09;与 redis1. 存储介质不同&#xff08;408选手应该都懂hh&#xff09;2. 数据结构优化3. I/O模型差异4. CPU缓存友好性5. 单线程与多线程差异6. 持久化与缓存…

哈尔滨网站建设注意哪些问题

在进行哈尔滨网站建设时&#xff0c;需要注意以下几个问题&#xff1a; 首先&#xff0c;要明确网站的定位和目标。网站建设的首要任务是明确网站的定位和目标&#xff0c;确定网站所要传达的信息和服务内容&#xff0c;以及面向的目标用户群体。哈尔滨作为一个具有浓厚地域特色…

Linux脚本:如何编写bash脚本统计多个相关进程的CPU占用率,以此统计系统中指定多进程的总的CPU使用率

目录 一、需求 二、分析 三、脚本示例 1、创建脚本 2、编写脚本 3、脚本编写注意事项 &#xff08;1&#xff09;CPU占用率列 &#xff08;2&#xff09;多进程实例 &#xff08;3&#xff09;权限 四、运行脚本 1、给予脚本可执行权限 2、运行脚本 五、优化脚本 …

linux live555编译以及rtsp服务器搭建

一、live555源码 下载&#xff1a;点击跳转 二、编译 1、往文件 config.linux里的 COMPILE_OPTS 添加以下两个参数 -DNO_STD_LIB 和 -DNO_OPENSSL1 &#xff0c;修改后如下&#xff1a; COMPILE_OPTS $(INCLUDES) -I/usr/local/include -I. -O2 -DNO_STD_LIB -DNO_OPENSS…

大数减法c++

这里写目录标题 key key 检查减数和被减数的大小&#xff0c;大的放前&#xff0c;小的放后确定结果是正数&#xff0c;还是负数&#xff0c;即符号位从低位开始减如果a[i]<b[i]&#xff0c;则向高位借1当10&#xff0c;a[i1]–;a[i]10 #include <iostream> #include…

【python】OpenCV—Coordinates Sorted Clockwise

文章目录 1、需求介绍2、算法实现3、完整代码 1、需求介绍 调用 opencv 库&#xff0c;绘制轮廓的矩形边框&#xff0c;坐标顺序为右下→左下→左上→右上&#xff0c;我们实现一下转化为熟悉的 左上→右上→右下→左下 形式 按照这样的顺序组织边界框坐标是执行透视转换或匹…

采用反相正基准电压电路的反相运算放大器(运放)

采用反相正基准电压电路的反相运算放大器(运放) 采用反相正基准电压电路的同相运算放大器&#xff08;运放&#xff09; 设计目标 输入ViMin输入ViMax输出VoMin输出VoMax电源电压Vcc电源电压Vee电源电压Vref-5V-1V0.05V3.3V5V0V5V 设计说明1 此设计使用具有反相正基准的反…

gite+picgo+typora打造个人免费笔记软件

文章目录 1️⃣个人笔记软件2️⃣ 配置教程2.1 使用软件2.2 node 环境配置2.3 软件安装2.4 gite仓库设置2.5 配置picgo2.6 测试检验2.7 github教程 &#x1f3a1; 完结撒花 1️⃣个人笔记软件 最近换了环境&#xff0c;没有之前的生产环境舒适&#xff0c;写笔记也没有劲头&…

盒须图boxplot 展示第6条线

正常情况下,盒须图是有5条线的,但是实际产品场景是需要6条线,看了下echarts官网,没看到可配置的地方,只能自己骚操作了,效果图如下: 重点:用两条x轴,第6条线挂在第二条x轴上,且第二条x轴不展示。 option = {...,xAxis: [{type: category,data: [Class1, Class2, Cl…

Web前端网页设计与制作(想起来哪里写哪里版)

本文技术栈基于HtmlCssJavaScript制作web页面以及功能实现的部分设计与展示&#xff0c;实际的网站开发会涉及更多的细节&#xff0c;包括但不限于用户认证、数据库存储、前端框架的使用、响应式设计、安全性措施等。 废话不说&#xff0c;直接看源码 1.index 首页&#xff1a…

【漏洞复现】泛微e-cology9 WorkflowServiceXml SQL注入漏洞

文章目录 前言漏洞描述影响范围 漏洞复现nuclei脚本 安全修复 前言 泛微协同管理应用平台e-cology是一套兼具企业信息门户、知识文档管理、工作流程管理、人力资源管理、客户关系管理、项目管理、财务管理、资产管理、供应链管理、数据中心功能的企业大型协同管理平台。 漏洞…

算法学习day16——刷题(仍然是数组)

一、图片平滑器 图像平滑器 是大小为 3 x 3 的过滤器&#xff0c;用于对图像的每个单元格平滑处理&#xff0c;平滑处理后单元格的值为该单元格的平均灰度。 每个单元格的 平均灰度 定义为&#xff1a;该单元格自身及其周围的 8 个单元格的平均值&#xff0c;结果需向下取整…

使用llama-cpp-python制作api接口

文章目录 概要整体操作流程技术细节小结 概要 使用llama-cpp-python制作api接口&#xff0c;可以接入gradio当中&#xff0c;参考上一节。 llama-cpp-python的github网址 整体操作流程 下载llama-cpp-python。首先判断自己是在CPU的环境下还是GPU的环境下。以下操作均在魔搭…

应用层——HTTP

像我们电脑和手机使用的应用软件就是在应用层写的&#xff0c;当我们的数据需要传输的时候换将数据传递到传输层。 应用层专门给用户提供应用功能&#xff0c;比如HTTP,FTP… 我们程序员写的一个个解决我们实际的问题都在应用层&#xff0c;我们今天来聊一聊HTTP。 协议 协议…

Java案例遍历集合中的自定义对象

目录 一&#xff1a;案例要求&#xff1a; 二案例分析&#xff1a; ​编辑三&#xff1a;具体代码&#xff1a; 四&#xff1a;运行结果&#xff1a; 一&#xff1a;案例要求&#xff1a; 二案例分析&#xff1a; 三&#xff1a;具体代码&#xff1a; Ⅰ&#xff1a; pack…

pyinstaller用法详解3

本文使用创作助手。 大家好&#xff0c;时隔多日&#xff0c;我又更新了pyinstaller的用法详解&#xff01; 当然&#xff0c;这一次要比之前更详细&#xff0c;十分详细。 谢谢大家的支持&#xff0c;我们现在开始&#xff01; 一、快速开始使用pyinstaller 我之前的文章…

Web3时代的教育技术革新:智能合约在学习管理中的应用

随着区块链技术的发展和普及&#xff0c;Web3时代正在为教育技术带来前所未有的革新和机遇。智能合约作为区块链技术的核心应用之一&#xff0c;不仅在金融和供应链管理等领域展示了其巨大的潜力&#xff0c;也在教育领域中逐渐探索和应用。本文将探讨智能合约在学习管理中的具…

Java 中的迭代器

Iterator (迭代器) 正是由于每一个容器都有取出元素的功能&#xff0c;这些功能定义都一样&#xff0c;所以对共性的取出功能进行了抽取&#xff0c;从而出现了Iterator接口。由于每一个容器的数据结构不一样&#xff0c;所以具体的实现方式也不同&#xff0c;每一个容器都在其…

[激光原理与应用-115]:南京科耐激光-激光焊接-焊中检测-智能制程监测系统IPM介绍 - 19 - 主要硬件的介绍、安装与调试

目录 一、概述 1.1 前言 1.2 系统组成 1.2.1 机柜版&#xff1a; 1.2.2 非机柜版 1.3适用范围 1.4 工作条件 1.5 安全说明 1.6 装箱清单 二、硬件安装 2.1 光学传感器安装 2.1.1 转接件安装 2.1.2 光路校准模块的安装与光路校准 2.1.3 光学传感器的安装 2.2 通…