当前位置: 首页 > news >正文

类和对象(上续)

前言:本文介绍类和对象中的一些比较重要的知识点,为以后的继续学习打好基础。

目录

拷贝构造

拷贝构造的特征:

自定义类型的传值传参

自定义类型在函数中的传值返回 

如果返回值时自定义的引用呢?

在什么情况下使用呢?

拷贝构造中的浅拷贝问题

 ​编辑

为什么会释放两次呢?

那么什么情况下需要深拷贝?

运算符重载 

运算符重载的基本语法:

类中运算符重载函数的调用的两种方法:

运算符重载与函数重载

运算符重载的特征:

运算符重载的价值:

如果将运算符重载成全局函数,就无法访问类中的私有成员了。

解决方法:

赋值运算符

调用拷贝构造与调用赋值重载的区别


拷贝构造

拷贝构造是一种特殊的构造函数

拷贝构造的特征:

1.是构造函数的重载

2.参数只有一个并且只能是引用

3.拷贝构造可以不显示写,编译器会自动生成默认构造。

浅拷贝(值拷贝)就是一个字节一个字节的拷贝。

编译器自动生成的默认拷贝的特点:对内置类型的成员,浅拷贝(值拷贝);对自定义类型的成员,拷贝需要调用其拷贝构造

#include <iostream>
using namespace std;
class Date
{
public:Date(int year,int month,int day){_year = year;_month = month;_day = day;}//拷贝构造Date(Date& d){cout << "拷贝构造" << endl;_year = d._year;_month = d._month;_day = d._day;}
private:int _year;int _month;int _day;
};
int main()
{Date d1(2024,6,10);Date d2(d1);//拷贝构造Date d3 = d2;//拷贝构造return 0;
}

自定义类型的传值传参

#include <iostream>
using namespace std;
class Date
{
public:int GetYear(){return _year;}int GetMonth(){return _month;}int GetDay(){return _day;}Date(int year,int month,int day){_year = year;_month = month;_day = day;}Date(Date& d){cout << "拷贝构造" << endl;_year = d._year;_month = d._month;_day = d._day;}
private:int _year;int _month;int _day;
};void f(Date d)
{cout << d.GetYear() << " " << d.GetMonth() << " " << d.GetDay() << endl;
}
int main()
{Date d1(2024,6,10);Date d2(d1);Date d3 = d2;f(d1);return 0;
}

以上代码的运行结果 

在给f函数传值传参时,调用了一次拷贝构造。

结论:自定义类型在进行传值传参时会进行拷贝构造。

如果拷贝构造的参数是自定义类型不是自定义的引用那么就会出现无穷递归调用

自定义类型在函数中的传值返回 

下面有一段代码,以这段代码为例讲一下该问题。

#include <iostream>
using namespace std;class Date
{public:Date(int year, int month, int day){_year = year;_month = month;_day = day;}
private:int _year;int _month;int _day;
};Date f(Date d)
{return d;
}int main()
{Date d1(2024, 6, 10);Date d2 = f(d1);return 0;
}

 

 

结论:如果返回值,是自定义类型,那么,返回时就会进行拷贝构造,创建临时对象,再将临时对象赋值给正在创建的类

用一段错误代码解释上面的结论:

Date f(Date& d)
{return d;
}int main()
{Date d1(2024, 6, 10);Date& d2 = f(d1);return 0;
}

 

上述错误代码的报错: 

 

原因是因为,临时对象具有常性,用d2来引用临时对象是会出现权限放大的问题,所以验证了上述的结论,如果加上const(权限平移)报错就会消失。 

而编译器为了提高效率往往会直接将其优化为一次拷贝构造

如果返回值时自定义的引用呢?

Date& f()
{Date d1(2023, 1, 2);return d1;
}int main()
{Date& d1 = f();return 0;
}

 因为,d1 实在函数中定义的对象,出了函数的作用域就会销毁。

栈帧的角度来理解,引用的本质是指针,f函数被销毁了,main函数中的d1仍指向f中的d1的那块已被销毁的空间

自定义类型的引用返回存在风险

在什么情况下使用呢?

出了函数的作用域生命周期没到,不构析对象还在,,那么就可以用引用 返回

出了函数的作用域生命周期到了,析构,对象不存在,那么就只能用传值返回

 

拷贝构造中的浅拷贝问题

以下代码存在浅拷贝问题

#include <stdlib.h>
#include <iostream>
using namespace std;
class Stack
{
public:Stack(int capacity = 4){cout << "Stack()" << endl;_arr = (int*)malloc(sizeof(int) * capacity);_capacity = capacity;_top = 0;}~Stack(){cout << "~Stack()"<<endl;free(_arr);_capacity = 0;_top = 0;}
private:int* _arr;int _top;int _capacity;
};int main()
{Stack st1(4);Stack st2(st1);return 0;
}

程序崩溃:

 

 

该代码的问题就在于对一块开辟的空间释放两次

为什么会释放两次呢?

因为没有显示写拷贝构造函数,所以用的是编译器自动生成的拷贝构造函数(浅拷贝),所以在拷贝构造st2时,使st2中_arr指向的空间与st1中的一样,最后分别调用析构函数时,就造成了对用一块开辟的空间释放两次。 

解决方案就是深拷贝

	Stack(Stack& st){_arr = (int*)malloc(sizeof(int) * st._capacity);//深拷贝_capacity = st._capacity;_top = st._top;}

那么什么情况下需要深拷贝?

总结:

1.如果没有管理资源,就不显示写拷贝构造,用默认拷贝构造就可以

2.都是自定义的成员,内置类型(内置类型不指向资源),也用默认拷贝;如果自定义类型的成员的内置类型指向资源,那么在该自定义类型中显示写拷贝构造

3.一般,不需要写析构函数,就需要写构造函数

4.内部有指针或一些值指向资源,显示写析构释放,通常需要写拷贝构造来完成深拷贝

运算符重载 

 

运算符重载的基本语法:

返回值类型 + operater+运算符(参数列表)

operator是关键字,operator和运算符一起构成函数名。

类中运算符重载函数的调用的两种方法:

    //在类中实现的+运算符重载(实现日期与天数的相加)Date operator+(int day){_day += day;while (_day > GetMonthDay(_year, _month)){_day -= GetMonthDay(_year, _month);_month++;if (_month > 12){_month = 1;_year++;}}return *this;}  //已经在类中写了一个加号重载的函数Date d1(2024, 6, 10);d1 + 100;//第一种调用方法d1.operator+(100);//第二种调用方法

运算符重载与函数重载

运算符重载和函数重载没有关系,是两回事,多个相同的运算符的重载是函数重载

比如<<(流插入)可以自动识别内置类型的原因就是对<<进行重载,构成了函数重载。

运算符重载的特征:

1.不能通过其他符号重载

2.必须有一个类类型的参数

3.含义不能改变(这里是建议,比如重载的+的含义是将两个数相加,而你写的含义是相减)

4.一般,参数比运算符操纵的操作数的数目少1,因为在参数列表中有隐含的this指针

5. .*    ::    sizeof   ?:   .   这五个操作符不能被重载,.*是用于类成员函数指针的访问,

如果想了解:函数指针到底需不需要解引用?类成员函数呢?_函数指针需要解引用吗-CSDN博客

   

运算符重载的价值:

运算符重载是运算符不仅限于操纵内置类型的数据,可以实现类与类之间,或类与内置类型直间的运算,可以增强代码的可读性

一个使用运算符重载的例子:

#include <iostream>
using namespace std;
class Date
{
public:Date(int year, int month, int day){_year = year;_month = month;_day = day;}//得到当前月份的天数int	GetMonthDay(int year, int month){int month_day[13] = { 0,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 month_day[month];}//重载+运算符实现日期与天数的相加Date operator+(int day){_day += day;while (_day > GetMonthDay(_year, _month)){_day -= GetMonthDay(_year, _month);_month++;if (_month > 12){_month = 1;_year++;}}return *this;}void Print(){cout << _year << " " << _month << " " << _day << endl;}
private:int _year;int _month;int _day;
};
int main()
{Date d1(2024, 6, 10);Date d2 = d1 + 100;d2.Print();return 0;
}

上述代码中的+的重载,是在类中实现的,或在类中声明,在类外实现。

如果将运算符重载成全局函数,就无法访问类中的私有成员了。

解决方法:

1.在类中实现成员的Get(获取成员)和Set(重新给成员赋值)的接口

2.将全局函数设为该类的友元

3.重载为成员函数(可以访问类的成员,但函数不在是全局函数)

这些方法比较建议第二种。

以下的代码是通过友元来实现全局减号的运算符重载

#include <iostream>
using namespace std;
class Date
{//友元就是在函数前加上一个关键字friend,并在相应的类中声明friend Date operator-(Date& d,int day);
public:Date(int year, int month, int day){_year = year;_month = month;_day = day;}int	GetMonthDay(int year, int month){int month_day[13] = { 0,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 month_day[month];}Date operator+(int day){_day += day;while (_day > GetMonthDay(_year, _month)){_day -= GetMonthDay(_year, _month);_month++;if (_month > 12){_month = 1;_year++;}}return *this;}void Print(){cout << _year << " " << _month << " " << _day << endl;}
private:int _year;int _month;int _day;
};//全局函数减号的重载
Date operator-(Date& d,int day)
{d._day -= day;while (d._day <= 0){if (d._month == 1){d._month = 12;d._year--;}else{d._month--;}d._day += d.GetMonthDay(d._year, d._month);}return d;
}



赋值运算符

赋值运算符重载也是6个默认成员函数之一

调用拷贝构造与调用赋值重载的区别

	Date d1(2024, 6, 10);Date d2 = d1;//拷贝构造Date d3(d1);//拷贝构造Date d4(2024, 2, 11);d4 = d1;//赋值重载

注意:上面代码中两个等号的调用方式容易混,但最后这两个有本质的区别。

结语:希望本文能够让你有所收获 。

相关文章:

类和对象(上续)

前言&#xff1a;本文介绍类和对象中的一些比较重要的知识点&#xff0c;为以后的继续学习打好基础。 目录 拷贝构造 拷贝构造的特征&#xff1a; 自定义类型的传值传参 自定义类型在函数中的传值返回 如果返回值时自定义的引用呢&#xff1f; 在什么情况下使用呢&#…...

【C++初阶学习】第十三弹——优先级队列及容器适配器

C语言栈&#xff1a;数据结构——栈(C语言版)-CSDN博客 C语言队列&#xff1a;数据结构——队列&#xff08;C语言版&#xff09;-CSDN博客 C栈与队列&#xff1a;【C初阶学习】第十二弹——stack和queue的介绍和使用-CSDN博客 前言&#xff1a; 在前面&#xff0c;我们已经…...

Java(十七)---ArrayList的使用

文章目录 前言1.ArrayList的简介2. ArrayList使用2.1.ArrayList的构造2.2.ArrayList的扩容机制(JDK17) 3.ArrayList的常见操作4. ArrayList的具体使用4.1.[杨辉三角](https://leetcode.cn/problems/pascals-triangle/description/)4.2.简单的洗牌游戏 5.ArrayList的问题及思考 …...

实验六、IPv4 地址的子网划分,第 2 部分《计算机网络》

你有没有发现&#xff0c;困的时候真的清醒不了。 目录 一、实验目的 二、实验内容 三、实验小结 一、实验目的 完成本练习之后&#xff0c;您应该能够确定给定 IP 地址和子网掩码的子网信息。 知道 IP 地址、网络掩码和子网掩码后&#xff0c;您应该能够确定有关该 IP 地…...

定个小目标之刷LeetCode热题(12)

这是一道简单题&#xff0c;使用位运算中的异或运算即可&#xff0c;异或运算有以下性质&#xff1a; 1、任何数异或 0 结果仍然是原来的数&#xff0c;即 a⊕0a 2、任何数和其自身做异或运算&#xff0c;结果是 0 所以我们只需要让数组里的所有元素进行异或运算得到的结果就…...

MYSQL内存占用查询语句

可以通过以下 SQL 语句查询相关配置参数的当前值&#xff1a; InnoDB 缓冲池大小 (innodb_buffer_pool_size)&#xff1a; SHOW VARIABLES LIKE innodb_buffer_pool_size;最大连接数 (max_connections)&#xff1a; SHOW VARIABLES LIKE max_connections;临时表大小 (tmp_table…...

HikariCP连接池初识

HikariCP的简单介绍 hikari-光&#xff0c;hikariCP取义&#xff1a;像光一样轻和快的Connetion Pool。这个几乎只用java写的中间件连接池&#xff0c;极其轻量并注重性能&#xff0c;HikariCP目前已是SpringBoot默认的连接池&#xff0c;伴随着SpringBoot和微服务的普及&…...

LeetCode136只出现一次的数字

题目描述 给你一个 非空 整数数组 nums &#xff0c;除了某个元素只出现一次以外&#xff0c;其余每个元素均出现两次。找出那个只出现了一次的元素。你必须设计并实现线性时间复杂度的算法来解决此问题&#xff0c;且该算法只使用常量额外空间。 解析 需要想到异或运算&#…...

html5实现端午节网站源码

文章目录 1.设计来源1.1 端午首页页面1.2 端午由来页面1.3 端午图集页面1.4 端午活动页面1.5 给我留言页面 2.效果和源码2.1 动态效果2.2 目录结构 源码下载 作者&#xff1a;xcLeigh 文章地址&#xff1a;https://blog.csdn.net/weixin_43151418/article/details/139524377 ht…...

echarts组件x轴坐标显示不全解决方法

1.旋转: 修改前: option {xAxis: {type: category,data: [Mon, Tue, Wed, Thu, Fri, Sat, Sun,Mon, Tue, Wed, Thu, Fri, Sat, Sun,Mon, Tue, Wed, Thu, Fri, Sat, Sun]},yAxis: {type: value},series: [{data: [120, 200, 150, 80, 70, 110, 130,120, 200, 150, 80, 70, 1…...

JS实现移动端的轮播图滑动事件

在移动端实现轮播图滑动事件&#xff0c;我们通常使用 touchstart、touchmove 和 touchend 这三个事件。下面是一个基本的示例&#xff0c;展示了如何使用原生JavaScript来创建一个简单的移动端轮播图滑动效果&#xff1a; HTML结构&#xff1a; <div id"carousel&qu…...

2024.6.10学习记录

1、代码随想录二刷 2、项目难点 review 3、计组复习...

RapidJSON

要在项目中使用 RapidJSON 库&#xff0c;需要首先下载并包含该库的头文件。以下是详细的步骤&#xff0c;包括如何下载、引用和使用 RapidJSON&#xff1a; 使用 CMake 引用 RapidJSON 如果你的项目使用 CMake 构建系统&#xff0c;可以按照以下步骤引用 RapidJSON&#xff…...

二叉树的创建

目录 一、二叉树的定义 二、代码定义 三、遍历二叉树 1、前序遍历 2、中序遍历 3、后序遍历 四、方法的使用 一、二叉树的定义 二叉树&#xff08;binary tree&#xff09;是指树中节点的度不大于2的有序树&#xff0c;它是一种最简单且最重要的树。二叉树的递归定义为&a…...

adb shell进入设备后的命令

目录 一、查看删除手机 /data/local/tmp/下的文件 二、设置权限 三、查看手机设备正在运行的服务 四、可能需要的adb 命令 一、查看删除手机 /data/local/tmp/下的文件 可以通过以下命令&#xff1a; adb shell # 进入设备 ls /data/local/tmp/ # 查看文件夹下的内容…...

【Android面试八股文】Java中静态内部类是什么?和非静态内部类的区别是什么?

文章目录 Java中静态内部类是什么?和非静态内部类的区别是什么?这道题想考察什么?考察的知识点考生应该如何回答什么是内部类,什么是静态内部类?静态内部类非静态内部类静态内部类和非静态内部类的区别静态内部类和普通内部类都有各自的用途和优势扩展一:使用静态内部类来…...

IDEA启动项目报java.lang.OutOfMemoryError: GC overhead limit exceeded

idea编译项目时报j ava.lang.OutOfMemoryError: GC overhead limit exceeded错误&#xff0c;教你两步搞定&#xff01; 第一步&#xff1a;打开help -> Edit Custom VM Options ,修改xms和xmx的大小&#xff0c;如下图&#xff1a; 第二步&#xff1a;File -> Settings…...

基于R语言BIOMOD2 及机器学习方法的物种分布模拟与案例分析

原文链接&#xff1a;基于R语言BIOMOD2 及机器学习方法的物种分布模拟与案例分析https://mp.weixin.qq.com/s?__bizMzUzNTczMDMxMg&mid2247606139&idx4&snf94ec30bfb5fa7ac0320403d49db3b66&chksmfa821e9ccdf5978a44a9ba96f6e04a121c0bbf63beea0940b385011c0b…...

【笔记2】Python编程:从入门到实践(第2版) - 埃里克·马瑟斯

第二部分 1、外星人入侵 Pygame包 2、数据可视化 Matplotlib 、Plotly 3、Web应用程序 Django 项目1&#xff1a;外星人入侵 第12章&#xff5e;第14章 使用Pygame包来开发一款2D游戏。 它在玩家每消灭一群向下移动的外星人后&#xff0c;将玩家提高一个等级。等级越高&…...

优质免费的 5 款翻译 API 接口推荐

当谈到翻译API时&#xff0c;我们通常指的是一种编程接口&#xff0c;它允许开发者将文本从一种语言翻译成另一种语言。这些API通常由专业的翻译服务提供商提供&#xff0c;如谷歌翻译 API、实时翻译API、腾讯翻译API、DeepL翻译API、Azure翻译API等。 这些API通常提供多种语言…...

雷电模拟器中控实现,直通源码

目录 前言 开发 需求 初始环境 UI搭建 功能实现 前言 本篇为易语言雷电模拟器中控项目实现操作&#xff0c;一般用于&#xff1a;脚本开发多线程模拟操作等起始模板框架&#xff0c;使用易语言原因为其前后端一体化&#xff0c;对于脚本开发而言更为方便。 开发 需求 以…...

从渲染管线到着色器Shader实践

浏览器渲染管线原理 浏览器渲染管线是浏览器将HTML、CSS和JavaScript转换为用户可见的网页的过程。这一过程涉及多个步骤,包括解析、布局、绘制和合成等。下面是浏览器渲染管线的详细原理: 解析(Parsing): HTML解析:浏览器下载HTML内容后,首先进行HTML解析,将HTML文本…...

LabVIEW开发实验室超导体电流特性测试系统

本系统旨在为学校实验室提供一个基于LabVIEW的超导体电流特性测试平台&#xff0c;通过精确测量超导体在不同温度和电流条件下的电学特性&#xff0c;帮助学生和研究人员深入理解超导体的物理性质。本文将从背景、目标、工作原理、使用方法、操作流程和注意事项等方面详细介绍该…...

C语言之main函数的返回值(在linux中执行shell脚本并且获取返回值)

一&#xff1a;函数为什么要返回值 &#xff08;1&#xff09;函数 在设计的时候是设计了参数和返回值&#xff0c;参数是函数的输入&#xff0c;返回值是数据的输出 &#xff08;2&#xff09;因为函数需要对外输出数据&#xff08;实际上是函数运行的一些结果值&#xff09;…...

【手撕面试题】Vue(高频知识点五)

每天10道题&#xff0c;100天后&#xff0c;搞定所有前端面试的高频知识点&#xff0c;加油&#xff01;&#xff01;&#xff01;在看文章的同时&#xff0c;希望不要直接看答案&#xff0c;先思考一下自己会不会&#xff0c;如果会&#xff0c;自己的答案是什么&#xff1f;想…...

C#有哪些方式实现回调函数、处理异步操作或响应某些条件时的动作

在C#中&#xff0c;除了使用event关键字来定义事件和回调函数&#xff08;事件处理器&#xff09;之外&#xff0c;还有几种其他方式来处理异步操作或响应某些条件时的动作&#xff1a; 委托&#xff08;Delegates&#xff09;&#xff1a; 委托类似于C/C中的函数指针&#x…...

Java:110-SpringMVC的底层原理(上篇)

SpringMVC的底层原理 在前面我们学习了SpringMVC的使用&#xff08;67章博客开始&#xff09;&#xff0c;现在开始说明他的原理&#xff08;实际上更多的细节只存在67章博客中&#xff0c;这篇博客只是讲一点深度&#xff0c;重复的东西尽量少说明点&#xff09; MVC 体系结…...

【HarmonyOS】鸿蒙应用子模块module资源如何获取

【HarmonyOS】鸿蒙应用子模块module资源如何获取 一、问题背景&#xff1a; 在多模块项目工程中&#xff0c;单个模块的资源不会放在主模块中&#xff0c;所以我们需要在子模块中访问自己的资源。如果使用默认的资源获取api&#xff0c;会提示找不到资源。 那如何获取子模块下…...

Centos X系统yum安装mysql数据库

安装之前需要将系统自带的mariadb-libs软件包删除。 检查是否存在mariadb-libs包。 yum list installed|grep mariadb-libs 删除mariadb-libs包 yum -y remove mariadb-libs 声明&#xff1a; 系统&#xff1a;CentOS-7-x86_64-DVD-2009 安装为最小化安装&#xff0c;没…...

Python语言在金融领域的应用探索

Python语言在金融领域的应用探索 Python语言&#xff0c;以其简洁、易读和强大的功能库&#xff0c;近年来在金融领域崭露头角。它不仅为数据分析师、量化分析师和交易员提供了强大的工具&#xff0c;还在风险管理、投资组合优化等方面发挥了重要作用。本文将深入剖析Python语…...

手机邮箱申请免费注册/seo最强

资料图&#xff1a;正在起飞的客运飞机。 中新网客户端北京1月15日电 (记者 程春雨)“为避免出现热点地区拥堵和票价过高情况&#xff0c;民航局在上海浦东、成都双流、三亚凤凰等10个热点机场开展国内航班延长运行时间试点&#xff0c;增加了航空公司统筹运力安排的灵活性&…...

做围棋题最好的网站/qq推广引流怎么做

一、 使用Autowired时注解下面出现了波浪线&#xff0c;仔细一看是这样的 二、出现原因 查阅了相关文档了解了一下&#xff0c;原来这个提示是spring framerwork 4.0以后开始出现的&#xff0c;spring 4.0开始就不推荐使用属性注入&#xff0c;改为推荐构造器注入和setter注入…...

储物柜厂家直销器厂家做网站/班级优化大师官网下载

服务器负载太大而影响程序效率也是很常见的&#xff0c;Apache服务器自带有一个叫AB(ApacheBench)的工具&#xff0c;可以对服务器进行负载测试 同时商城的秒杀功能也会被高负载影响&#xff0c;从而导致超卖现象 首先安装xampp软件进入 c:/xampp/apache/bin 基本用法: ab …...

电影网站空间配置/宁波seo免费优化软件

项目紧迫&#xff0c;需在短时间内交付成果&#xff0c;新团队成员&#xff0c;吐嘈之前数据库设计太low&#xff0c;很难看懂数据库表结构间的关系&#xff0c;为了使新同事更好的了解数据库表结构&#xff0c;特意使用powerDesigner对oracle、mysql数据库逆向生成物理图、概念…...

重庆铜梁网站建设价格/最近新闻热点大事件

1.方程ax2bxc0;一元二次方程。求根△b2-4ac;若△<0方程无实根△>0,方程有两个不相同的实根x1 x2若△0&#xff0c;方程有两个相同的实根x(-b加减根号下b*b-4ac)/2*a 调试后&#xff1a; 2. 输入一个年份&#xff0c;判断是否是闰年(能被4整除却不能被100整除的年份)。世纪…...

俄文企业网站建设/整合营销传播名词解释

1、实现效果&#xff1a; 案例描述&#xff1a;当用户单击不同的导航时&#xff0c;与其对应的内容回相应的呈现。 案例要求&#xff1a;使用jquery制作实现tab选项卡单击切换效果。 2、实现思路&#xff1a; &#xff08;1&#xff09;divcss布局&#xff0c;制作选项卡和对…...