类和对象中的默认成员函数(构造,拷贝构造,析构......)深入了解类和对象

文章目录

  • 类的6个默认成员函数
    • 构造函数
      • 总结构造函数
    • 析构函数
      • 总结析构函数
    • 拷贝构造函数
      • 总结拷贝构造函数
    • 赋值运算符重载
    • 取地址重载和const取地址重载

类的6个默认成员函数

一个什么都不写的类我们称之为“空类”

class Test
{}

我们什么都没写,这里看着空空的,可是它真的什么都没有吗?
所以今天我们来探究一下,类里面都有那些好玩的

构造函数

什么叫做构造函数,说白了构造->初始化。就这么理解,构造函数的作用就是初始化函数且在对象整个生命周期内只会调用一次构造函数,那么它是如何实现呢,我们看看(用的是日期)

class Date
{
public:
//这就是一个构造函数的雏形Date(){}
private:int _year;int _month;int _day;
};

它是由类名当作名称的一个函数,那么怎样体现它的初始化呢?

class Date
{
public:
//这就是一个构造函数的雏形Date(int year,int month,int day){_year = year;_month = month;_day = day;}
private:int _year;int _month;int _day;
};int main()
{
//对一个对象进行实例化Date p1(2024,5,1);return 0;
}

这就是最基础能体现构造函数方法的一串代码
结果如下:
在这里插入图片描述
我们发现我们并没有显示的去调用这个函数,就是说我们并没有在
Data p1(2024,5,1)这行代码下面去写Date()我们没有调用是编译器自动帮我们去调用的,这样一看还挺智能奥,这样就有效的阻止我们有时候忘记初始化的问题。
问题又来了,那么为什么说它是我们类中的一个默认成员函数呢?我们不写构造函数,这个类里真的还有默认构造函数吗?我们来看这样一个测试

class Date
{
private:int _year;int _month;int _day;
};
int main()
{Date p1;return 0;
}

在这里插入图片描述
我们发现了什么?这代码编译居然能过?说明我们这里产生了默认构造这个默认的构造函数是无参的,也就是说你别乱写给个参数那指定报错,但是值是随机值有兴趣可以自己调试看看。
有人问了,它给个随机值,也没啥用,那么这个
默认的构造函数有什么用呢?
我们知道C++将类型分为内置类型和自定义类型,什么是内置类型?(int,char,float…)什么是自定义类型?显而易见就是我们的类或者结构体
那么如果是这种情景呢?

class Date
{
public://无参的构造函数Date(){cout << "我是不带参的" << endl;}//带参的构造函数Date(int year, int month, int day){_year = year;_month = month;_day = day;cout << "我是带参的" << endl;}
private:int _year;int _month;int _day;
};class T
{
private:
int hour;
int minute;
int second;
Date p;
};

这就有意思了我们一个类中的成员变量是另一个自定义类型的对象,那么当我们在这里不显示的写构造函数的时候我们去调用会发现,这里的自定义类型的对象会去调用它的构造函数(不是默认构造),对于我们的内置类型却不做任何处理,也就是和之前的默认构造一样但是对于自定义类型会去调用它的构造函数,这很有意思。
在这里插入图片描述
看见了嘛,这里是我不是带参的这句话输出了两次,这可以说明默认构造函数的价值还是很大的,它对内置类型不做处理,对于自定义类型会去走自定义类型的默认构造

回来再看如果我们放开前面写的构造函数看看。
在这里插入图片描述
这里就会报错,但是报错的原因是什么呢?没有合适的默认构造可用,这说明当我们显示的写了一个构造函数之后编译器就不会生成那个默认的构造函数,这就导致了如果我们写了构造函数我们就需要传参,实例化一个完整的对象
注意:
构造函数也可也重载
我们来举个例子
在这里插入图片描述
这里就能看出来,两个不同的对象调用了不同的构造函数

总结构造函数

用途:初始化
特性:不显示的写编译器可以默认生成一个
无返回值
函数名就是类名
可以进行重载

析构函数

刚说完构造函数的作用就相当于初始化,那么析构函数就是它的死对头,它是用来销毁的,在我们以前手写栈的时候我们会用到自己写的Destroy()函数用来释放我们动态内存开辟的空间,但是当我们有了析构函数我们就不需要再去显示的调用这个Destroy()函数了,编译器会自己调用。
我们先写个栈的雏形,但是我们不实现奥,要看栈的完整实现,可以点这里用的是C语言
我们来继续讨论这里的析构函数的写法以及特点

class Stack
{
public:Stack(){int* tmp;tmp = (int*)malloc(sizeof(int) * 4);if (tmp == nullptr)exit(-1);_arry = tmp;_size = 0;_capacity = 4;cout << "Stack()" << endl;}
//这就是析构函数---我们的Destroy~Stack(){free(_arry);_size = 0;_capacity;cout << "~Stack()" << endl;}void Stack_Push(int x){////......//}private:int* _arry;int _size;int _capacity;
};int main()
{Stack st;return 0;
}

我们编译一下
在这里插入图片描述
如果说构造函数你有把握你不会忘记init()也就是你不会忘记初始化,但是当程序写的七七八八的时候你是否会忘记要释放内存呢?如果导致内存泄漏了呢?这些都是问题,但是如果你写了析构函数那么,我们就不用担心遗忘的问题,编译器会自动调用这里的析构函数。
那么我们如何能看到编译器自带的默认析构函数呢?

class Date
{
public:Date(){}Date(int year, int month, int day){_year = year;_month = month;_day = day;}~Date(){cout<<"~Date()"<<endl;}
private:int _year;int _month;int _day;
};class T
{
private:
int hour;
int minute;
int second;
Date p;
};

在这里插入图片描述
有意思吧,我们没有去调用这里的析构函数,但是会有存在在T这个类的默认析构函数的调用,这里的默认析构函数和构造函数一样对于自定义类型会去找其析构函数,对于自定义类型由于内置类型销毁时不需要资源的清理,OS直接回收内存就行所以对于内置类型不做处理,这里是T的默认析构,调用了Date的析构函数,也就是说默认析构是存在的
那么析构函数可以重载吗??
当然是不可以的
析构函数只能有一个

总结析构函数

作用:Destroy,进行内存的回收或者是资源的清理
特性:
函数名就是类名前面加一个~取反的那个符号或者是说小波浪号
不可以重载析构函数
没有返回值
在对象生命周期结束的时候自动调用

拷贝构造函数

这可是个大头,很多人都可能不太能理解什么是拷贝构造函数,为此我讲这个也想了很久该怎么叙述这个概念
什么是拷贝构造函数,它和构造函数有啥区别?
拷贝构造是构造函数的一种重载形式
那么为什么要有拷贝构造构造函数不够我们用的吗?
我们先来看看写法

class Date
{
public:Date(const Date& d){_year = d._year;_month = d._month;_day = d._day;cout << "Date(const& )" << endl;}Date(int year = 1, int month = 1, int day = 1){_year = year;_month = month;_day = day;}~Date(){cout << "~Date()" << endl;}
private:int _year;int _month;int _day;
};int main()
{Date p1;Date p2(p1);return 0;
}

在这里插入图片描述
当我们用一个自定义类型的对象作为参数去初始化另一个自定义类型的对象的时候我们就会调用我们的拷贝构造,它本质作用起始也是初始化,但是它的用处有很多可以作为返回值,参数。。。。
刚刚是我们主动写的拷贝构造,来我们看看编译器自主实现的默认拷贝构造
在这里插入图片描述
可以看到我们利用p1去初始化p2是可以成功的,但是我们并没有显示的写出来拷贝构造,这也能说明默认拷贝构造的存在
但是
在这里插入图片描述
这里能看出来他们的地址并不指向同一块空间,这说明编译器自带的默认拷贝构造是一种浅拷贝也就是值的拷贝,这种默认拷贝构造可以完成很大多数的情况,但是我们来看看这种

typedef int DataType;
class Stack
{
public:Stack(size_t capacity = 10){_array = (DataType*)malloc(capacity * sizeof(DataType));if (nullptr == _array){perror("malloc申请空间失败");return;}_size = 0;_capacity = capacity;}void Push(const DataType& data){// CheckCapacity();_array[_size] = data;_size++;}~Stack(){if (_array){free(_array);_array = nullptr;_capacity = 0;_size = 0;}}
private:DataType* _array;size_t _size;size_t _capacity;
};
int main()
{Stack s1;s1.Push(1);s1.Push(2);s1.Push(3);s1.Push(4);Stack s2(s1);return 0;
}

既然说过了默认拷贝构造是将值进行拷贝,那么通过s1去初始化s2的时候,两个array都指向了同一块空间,那么我们曾经写过的析构函数登场了,既然你有两个对象,那么我就要析构两次没问题吧?s2先销毁,那么析构函数第一次就把array这块儿空间给销毁了,那么在销毁s1的时候,析构函数它又来了,又得销毁一次,同一块空间可以被销毁两次吗??所以这就能说明在没有进行动态内存申请的时候我们利用默认的拷贝构造是可以完成大部分事情的,但是当涉及到动态内存申请的时候我们就必须得去显示的写出拷贝构造。
那么还有一个问题我们需要解决那就是为什么拷贝构造的参数是一个同类类型的引用了
拷贝构造的参数只能是同类类型的引用,第一点是因为你只能拿同类型的去初始化一个同类型的对象这是第一点,当你用传值的方式去初始化的时候那么就会引发一种无穷递归的情况。
这是为什么呢?
当你的参数是同类型的对象的时候,形参是实参的一份临时拷贝,你得先拷贝到这个临时对象上才能进行操作
也就是
实参 ——>拷贝——>形参
这么一个过程但是你拷贝的时候需要调用拷贝构造因为你在用一个同类型去初始化一个同类型的对象,那么好了你拷贝的时候又建立了一个拷贝构造的对象,这个拷贝构造的对象作为实参又要去拷贝一个对象当作形参,在这个中途就会引发无穷递归根本到不了形参这一步,所以我们用的是传引用当作参数,直接让这个形参就是实参的别名,这样就不用经过拷贝这一步就不会引发无穷递归
在这里插入图片描述

总结拷贝构造函数

作用:仍然是初始化,但是和构造函数有不同,作用点也不一样
特性:
是构造函数的一种重载
当用同类型的对象去初始化另一个同类型的对象的时候会调用
同类型的对象作为返回值的时候会调用
同类型的对象做参数的时候会调用
这里还有很多好玩的比如说编译器的自我优化也会提到构造函数和拷贝构造目前就讲这些,后面会提及

赋值运算符重载

之前我们写过运算符重载的篇章可以运算符重载
点击这里可以看到,但是我们还是要单拿赋值运算符重载来说一下,因为它是编译器默认生成的一个成员函数,我们可以测试一下看能否看见这一现象
在这里插入图片描述
我们可以发现我们没有写赋值操作符,但是我们去直接使用的时候居然编译通过了,说明在这个类中有一个不显示写的赋值运算符,但是它也是浅拷贝,也就是把值赋值给了另一个对象,但是大部分操作的时候这个功能就够用了
所以我们知道编译器帮助我们实现了一个赋值运算符的重载就好还有两个重载分别是取地址重载和const取地址重载

取地址重载和const取地址重载

其实这两个部分都没什么好讲的,编译器自主实现的这两个运算符重载就足够满足大多数的情况了,就是取这个对象的地址的时候就可以调用

class Date
{ 
public :Date* operator&(){return this ;}const Date* operator&()const{return this ;}
private :int _year ; // 年int _month ; // 月int _day ; // 日
};

这两个运算符一般不需要重载,使用编译器生成的默认取地址的重载即可,只有特殊情况,才需
要重载,比如想让别人获取到指定的内容!

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

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

相关文章

对2023年图灵奖揭晓看法

2023年图灵奖揭晓&#xff0c;你怎么看&#xff1f; 2023年图灵奖&#xff0c;最近刚刚颁给普林斯顿数学教授 Avi Wigderson&#xff01;作为理论计算机科学领域的领军人物&#xff0c;他对于理解计算中的随机性和伪随机性的作用&#xff0c;作出了开创性贡献。这些贡献不仅推…

用FPGA+DAC输出“心”形波

1.前言 之前在做信号处理的时候整了一下活&#xff0c;用FPGADAC&#xff08;数模转换器&#xff09;&#xff0c;输出了一个爱心形状的波形&#xff0c;今天整理资料的时候偶然发现了他&#xff0c;现在把他分享出来。当时将DAC的输出接在示波器上显示如下图所示&#xff1a; …

IDEA创建Tomcat/Servlet项目

作者&#xff1a;私语茶馆 1.前言 利用Idea创建一个Java EE的Tomcat Web项目&#xff0c;记录一下过程。 Jakarta EE介绍&#xff1a;以前被称为Java EE&#xff08;Java Platform, Enterprise Edition&#xff09;&#xff0c;但在Oracle将Java EE相关的技术和知识产权转移到…

如何从 iPhone 恢复已删除或丢失的联系人?

不小心删除了您的 iPhone 联系人&#xff1f;不用担心。我们将向您展示如何从 iPhone或 iPad恢复已删除或丢失的联系人。当您从 iPhone 中删除联系人时&#xff0c;您可能认为无法将其恢复。但事实是&#xff0c;您可以从 iPhone 或 iPad 恢复已删除的联系人&#xff0c;因为它…

vue3实现移动端,PC端响应式布局

纯移动端|PC端 这种适用于只适用一个端的情况 方法&#xff1a;amfe-flexible postcss-pxtorem相结合 ① 执行以下两个命令 npm i -S amfe-flexible npm install postcss-pxtorem --save-dev② main.js文件引用 import amfe-flexible③ 根目录新建一个postcss.config.js文件…

rancher/elemental 构建不可变IOS(一)

一、什么是elemental Elemental 是 Rancher 的一个变种&#xff0c;专注于提供一个更轻量级的 Kubernetes 发行版。它旨在提供简化的部署和管理体验&#xff0c;同时保持 Kubernetes 的灵活性和强大功能。Elemental 通常针对较小的部署场景或资源受限的环境&#xff0c;例如测…

16册 | 移动机器人(自动驾驶)系列

此文档整理推荐了16本移动机器人&#xff08;自动驾驶&#xff09;相关的书籍&#xff0c;内容包括&#xff1a;ROS、机器人基础开发、分布式机器人控制、集群机器人控制、嵌入式机器人、多传感器融合等等。 学习&#xff0c;切勿急于求成&#xff0c;读书自学&#xff0c;需多…

讯饶科技 X2Modbus 敏感信息泄露

讯饶科技 X2Modbus 敏感信息泄露 文章目录 讯饶科技 X2Modbus 敏感信息泄露漏洞描述影响版本实现原理漏洞复现修复建议 漏洞描述 X2Modbus是一款功能很强大的协议转换网关&#xff0c; 这里的X代表各家不同 的通信协议&#xff0c;2是To的谐音表示转换&#xff0c;Modbus就是最…

uniapp 桌面应用插件 Ba-Launcher

简介&#xff08;下载地址&#xff09; Ba-Launcher 可以让你的应用成为简单的桌面应用&#xff0c;如需扩展功能&#xff0c;请联系我。 截图展示 可关注博客&#xff0c;实时更新最新插件&#xff1a; uniapp 常用原生插件大全 使用方法 使用方法也很简单&#xff0c;在插…

.net core ef 连表查询

Information和TypeInfo连表查询 类似&#xff1a; select st.Title1,si.* from [Star_Information] si left join Star_TypeInfo st on si.typeId2st.id 先在EfCoreDbContext.cs配置 protected override void OnModelCreating(ModelBuilder builder){base.OnModelCreating(b…

Sentinel 控制台学习

引言 上篇文章已经讲过 SpringCloud Sentinel集成到微服务项目中&#xff0c;接下来我们继续学习怎么使用sentinel控制台对微服务进行限流&#xff0c;熔断&#xff0c;降级等一系列操作。 控制台 接下来我们单独讲解每一个菜单按钮 实时监控 实时监控&#xff1a; 可以看到…

【项目构建】04:动态库与静态库制作

OVERVIEW 1.编译动态链接库&#xff08;1&#xff09;编译动态库&#xff08;2&#xff09;链接动态库&#xff08;3&#xff09;运行时使用动态库 2.编译静态链接库&#xff08;1&#xff09;编译静态库&#xff08;2&#xff09;链接静态库&#xff08;3&#xff09;运行时使…

免费的单片机物联网MQTT平台选择

目的是多设备接入中控&#xff0c;平台只做转发。 选择巴法云&#xff1a;巴法科技&巴法云-巴法设备云-巴法物联网云平台 clientId是私钥uid&#xff1a; 多设备 clientId 填同一个 uid 都是可以的。平台应该是加了后缀区分。 支持自定义topic&#xff0c;操作简单&#x…

2024.5.5 机器学习周报

引言 Abstract 文献阅读 1、题目 SuperGlue: Learning Feature Matching with Graph Neural Networks 2、引言 本文介绍了SuperGlue&#xff0c;这是一种神经网络&#xff0c;它通过联合寻找对应关系并拒绝不匹配的点来匹配两组局部特征。通过求解一个可微的最优运输问题…

TikTok引流中海外云手机的实用功能分享

在当下&#xff0c;TikTok已成为全球范围内最受欢迎的社交媒体平台之一&#xff0c;拥有着庞大的用户群体和潜在的商业机会。为了在TikTok上实现更好的引流效果&#xff0c;利用海外云手机成为了一个明智的选择。接下来&#xff0c;我们将深入探讨海外云手机的功能以及它如何助…

跳出框架:Facebook的创新策略与社交影响

1. 引言 在数字化时代&#xff0c;社交媒体如同一面镜子&#xff0c;反映出我们社会的多元性和变革。Facebook&#xff0c;作为这面镜子中最明亮的一个&#xff0c;不仅改变了人们的日常生活&#xff0c;更深刻地塑造了社交、文化和经济的面貌。本文将深入探讨Facebook的创新策…

Maven3.9.6下载安装教程

(/≧▽≦)/~┴┴ 嗨~我叫小奥 ✨✨✨ &#x1f440;&#x1f440;&#x1f440; 个人博客&#xff1a;小奥的博客 &#x1f44d;&#x1f44d;&#x1f44d;&#xff1a;个人CSDN ⭐️⭐️⭐️&#xff1a;Github传送门 &#x1f379; 本人24应届生一枚&#xff0c;技术和水平有…

BST二叉搜索树

概念 二叉搜索树&#xff08;Binary Search Tree&#xff0c;简称BST&#xff09;&#xff0c;又称为二叉排序树或二叉查找树&#xff0c;是一种特殊的二叉树数据结构。它具有以下基本性质&#xff1a; 节点的值的有序性&#xff1a;对于BST中的任意一个节点&#xff0c;其左…

交通 | 电动汽车车辆路径问题及FRVCP包的调用以及代码案例

编者按&#xff1a; 电动汽车的应用给车辆路线问题带来了更多的挑战&#xff0c;如何为给定路线行驶的电动汽车设计充电决策是一个需要解决的难题&#xff0c;本文介绍了开源python包frvcpy使用精确式算法对该问题求解。 文献解读&#xff1a;Aurelien Froger, Jorge E Mendo…

H.265 与 H.264 的主要区别

H.265 与 H.264 的主要区别 H.265 与 H.264 的主要区别各模块技术差异汇总宏块划分帧内预测模式帧间预测模式去块滤波ALF自适应环路滤波采样点自适应偏移&#xff08;Sample Adaptive Offset&#xff09;滤波并行化设计TileEntropy sliceDependent SliceWPP&#xff08;Wavefro…