【C++】C++入门—初识构造函数 , 析构函数,拷贝构造函数,赋值运算符重载

在这里插入图片描述

C++入门

  • 六个默认成员函数
  • 1 构造函数
    • 语法
    • 特性
  • 2 析构函数
    • 语法
    • 特性
  • 3 拷贝构造函数
    • 特性
  • 4 赋值运算符重载
    • 运算符重载
    • 赋值运算符重载
    • 特例:前置++ 与 后置++
      • 前置++:返回+1之后的结果
      • 后置++:
  • Thanks♪(・ω・)ノ谢谢阅读!!!
  • 下一篇文章见!!!

六个默认成员函数

如果一个类中什么成员都没有,简称为空类。
空类中真的什么都没有吗? 并不是
任何类在什么都不写时,编译器会自动生成以下6个默认成员函数。
默认成员函数:用户没有显式实现,编译器会生成的成员函数称为默认成员函数
我们实现了,编译器就不会生成了
在这里插入图片描述

1 构造函数

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

语法

  1. 函数名与类名相同。
  2. 无返回值
  3. 对象实例化时编译器自动调用对应的构造函数
  4. 构造函数可以重载(最好实现一个全缺省的构造函数)
class Date {
public:Date(int year = 2024, int month = 1, int day = 1) {_year = year;_month = month;_day = day;}void show() {cout << this->_year << "-" << this->_month << "-" << this->_day << endl;}
private:int _year;int _month;int _day;
};int main() {Date today(2024, 2, 18);//默认构造Date yesterday(2024, 2, 17);//默认构造today.show();yesterday.show();return 0;
}

来看效果在这里插入图片描述

特性

  1. 如果类中没有显示定义构造函数,C++编译器会自动生成一个无参的默认构造函数,一旦用户显示定义,编译器将不在生成。

  2. 关于编译器生成的默认成员函数,有个疑惑:不实现构造函数的情况下,编译器会生成 默认的构造函数。但是看起来默认构造函数又没什么用?Date对象调用了编译器生成的默认构造函数,但是Date对象_year / _month / _day,依旧是随机值。也就说在这里编译器生成的默认构造函数并没有什么用??
    解答:C++把类型分成内置类型(基本类型)和自定义类型。内置类型就是语言提供的数据类型,如:int/char…,自定义类型就是我们使用class/struct/union等自己定义的类型,看看下面的程序,就会发现编译器生成默认的构造函数会对自定类型成员 _t 调用的它的默认成员函数。

class Time
{
public:Time(){cout << "Time()" << endl;_hour = 0;_minute = 0;_second = 0;}
private:int _hour;int _minute;int _second;
};
class Date
{private:// 基本类型(内置类型)int _year;int _month;int _day;// 自定义类型Time _t;
};
int main()
{Date d;return 0;
}

上面程序会对 _t 进行默认构造,由于我们编写了构造函数,_t 中 的内容成功初始化,但是_year / _month / _day缺依然是随机值。

  1. 无参的构造函数和全缺省的构造函数都称为默认构造函数,并且默认构造函数只能有一个。注意:无参构造函数、全缺省构造函数、我们没写编译器默认生成的构造函数,都可以认为是默认构造函数

2 析构函数

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

语法

  1. 析构函数名是在类名前加上字符 ~
  2. 无参数无返回值类型。
  3. 一个类只能有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。注意:析构函数不能重载
  4. 对象生命周期结束时,C++编译系统系统自动调用析构函数。
    下面的栈可以帮助我们理解析构函数的作用
typedef int DataType;
class Stack
{
public:Stack(size_t capacity = 3){_array = (DataType*)malloc(sizeof(DataType) * capacity);if (NULL == _array){perror("malloc申请空间失败!!!");return;}_capacity = capacity;_size = 0;}void Push(DataType data){// CheckCapacity();_array[_size] = data;_size++;}// 析构函数~Stack(){	//如果 不为空if (_array){   // 释放指针free(_array);//初始化_array = NULL;_capacity = 0;_size = 0;}}
private:DataType* _array;int _capacity;int _size;
};
void TestStack()
{Stack s;s.Push(1);s.Push(2);//生命周期结束自动析构清理
}

特性

关于编译器自动生成的析构函数,是否会完成一些事情呢?下面的程序我们会看到,编译器生成的默认析构函数,对自定类型成员调用它的析构函数。

class Time
{
public:~Time(){cout << "~Time()" << endl;}
private:int _hour;int _minute;int _second;
};
class Date
{
private:// 基本类型(内置类型)int _year = 1970;int _month = 1;int _day = 1;// 自定义类型Time _t;
};
int main()
{Date d;return 0;
}

调用自定义类型 time 的析构函数
在这里插入图片描述
注意 :
析构函数的调用顺序,先创建先销毁,先销毁局部变量,在销毁全局变量。
如果类中没有申请资源时,析构函数可以不写,直接使用编译器生成的默认析构函数,比如Date类;有资源申请时,一定要写,否则会造成资源泄漏,比如Stack类

3 拷贝构造函数

拷贝构造函数:只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰),在用已存在的类类型对象创建新对象时由编译器自动调用

特性

  1. 拷贝构造是构造函数的一个重载形式。
  2. 拷贝构造函数的参数只有一个且必须是类类型对象的引用,使用直接的传值编译器会直接报错,因为会引发无穷递归调用。
    原因:传值拷贝时
    第一步:开辟一个临时空间;
    第二步:由于临时空间是需要构造的,重新调用拷贝构造函数(无穷递归形成…)

在这里插入图片描述

  1. 若未显式定义,编译器会生成默认的拷贝构造函数。 默认的拷贝构造函数对象按内存存储按字节序完成拷贝,这种拷贝叫做浅拷贝,或者值拷贝。
  2. 浅拷贝不能实现复杂的类拷贝,涉及指针等内容会拷贝失败。
  3. 拷贝构造函数典型调用场景:
    使用已存在对象创建新对象
    函数参数类型为类类型对象
    函数返回值类型为类类型对象

4 赋值运算符重载

运算符重载

C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有其返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。
函数名字为:关键字operator后面接需要重载的运算符符号。
函数原型:返回值类型 operator"操作符" (参数列表)

注意:

  1. 不能通过连接其他符号来创建新的操作符:比如operator@
  2. 重载操作符必须有一个类类型参数
  3. 用于内置类型的运算符,其含义不能改变,例如:内置的整型+,不 能改变其含义作为类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐藏的this
  4. .* :: sizeof ?: . 注意以上5个运算符不能重载。这个经常在笔试选择题中出现。

来看样例:

class Date {
public:Date(int year = 2024, int month = 1, int day = 1) {_year = year;_month = month;_day = day;}bool operator==( const Date& d2) {return _year == d2._year&& _month == d2._month&& _day == d2._day;}void show() {cout << _year << "-" << this->_month << "-" << this->_day << endl;}
private:int _year;int _month;int _day;
};int main() {Date today(2024, 2, 18);Date yesterday(2024, 2, 17);today.show();yesterday.show();cout << "operator==()\n" << (today == yesterday) << endl;return 0;
}

在这里插入图片描述不相等返回假。

赋值运算符重载

  1. 赋值运算符重载格式
    参数类型:const T&,传递引用可以提高传参效率
    返回值类型:T&,返回引用可以提高返回的效率,有返回值目的是为了支持连续赋值
    检测是否自己给自己赋值
    返回*this :要复合连续赋值的含义
class Date {
public:Date(int year = 2024, int month = 1, int day = 1) {_year = year;_month = month;_day = day;}//运算符重载bool operator==( const Date& d2) {return _year == d2._year&& _month == d2._month&& _day == d2._day;}//赋值运算符重载Date& operator=(const Date& d){if(this != &d){_year = d._year;_month = d._month;_day = d._day;}return *this;}void show() {cout << _year << "-" << this->_month << "-" << this->_day << endl;}
private:int _year;int _month;int _day;
};int main() {Date today(2024, 2, 18);Date day = today;today.show();day.show();return 0;
}

在这里插入图片描述
可以成功赋值。

  1. 赋值运算符只能重载成类的成员函数不能重载成全局函数
    原因:赋值运算符如果不显式实现,编译器会生成一个默认的。此时用户再在类外自己实现一个全局的赋值运算符重载,就和编译器在类中生成的默认赋值运算符重载冲突了,故赋值运算符重载只能是类的成员函数
  2. 用户没有显式实现时,编译器会生成一个默认赋值运算符重载,以值的方式逐字节拷贝注意:内置类型成员变量是直接赋值的,而自定义类型成员变量需要调用对应类的赋值运算符重载完成赋值。

既然编译器生成的默认赋值运算符重载函数已经可以完成字节序的值拷贝了
还需要自己实现吗?当然像日期类这样的类是没必要的。那么下面的类呢?验证一下试试?

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;s2 = s1;return 0;
} 

这里会发现下面的程序会崩溃掉?这里就需要我们以后讲的深拷贝去解决。
注意:如果类中未涉及到资源管理,赋值运算符是否实现都可以;一旦涉及到资源管理则必须要实现

特例:前置++ 与 后置++

前置++:返回+1之后的结果


// 注意:this指向的对象函数结束后不会销毁,故以引用方式返回提高效率
Date& operator++()
{_day += 1;return *this;
}

后置++:

前置++和后置++都是一元运算符,为了让前置++与后置++形成能正确重载
C++规定:后置++重载时多增加一个int类型的参数,但调用函数时该参数不用传递,编译器自动传递
注意:
后置++是 先使用后+1,因此需要返回+1之前的旧值,故需在实现时需要先将this保存
一份,然后给this+1,


Date operator++(int)
{Date temp(*this);_day += 1;// temp是临时对象,因此只能以值的方式返回,不能返回引用return temp;
}

Thanks♪(・ω・)ノ谢谢阅读!!!

下一篇文章见!!!

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

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

相关文章

算法练习-01背包问题【含递推公式推导】(思路+流程图+代码)

难度参考 难度&#xff1a;困难 分类&#xff1a;动态规划 难度与分类由我所参与的培训课程提供&#xff0c;但需 要注意的是&#xff0c;难度与分类仅供参考。且所在课程未提供测试平台&#xff0c;故实现代码主要为自行测试的那种&#xff0c;以下内容均为个人笔记&#xff0…

Shiro反弹shell和权限绕过含工具包

★★免责声明★★ 文章中涉及的程序(方法)可能带有攻击性&#xff0c;仅供安全研究与学习之用&#xff0c;读者将信息做其他用途&#xff0c;由Ta承担全部法律及连带责任&#xff0c;文章作者不承担任何法律及连带责任。 1、前言 反序列化漏洞原理和Shiro反序列化漏洞原理请参…

如何使用Sora?Sora小白教程一文通

如果需要使用Sora或者GPT4&#xff0c;请参考文章&#xff1a;如何使用Sora&#xff1f;Sora小白教程一文通 什么是Sora Sora是OpenAI于2024年2月18日凌晨发布的新的文生视频大模型&#xff0c;名为 “ Sora ”。 从OpenAI在官网展示的Sora生成视频的效果来看&#xff0c;在生…

day34打卡

day34打卡 860. 柠檬水找零 解法&#xff0c;贪心&#xff1a;局部最优&#xff1a;遇到账单20&#xff0c;优先消耗美元10&#xff0c;完成本次找零 -》全局最优&#xff1a;完成全部账单的找零。 遇到5&#xff0c;直接收下遇到10&#xff0c;找一个5元遇到20&#xff0c;…

软件实例分享,台球厅收费系统电脑桌球店计时软件及灯控线路图教程

软件实例分享&#xff0c;台球厅收费系统电脑桌球店计时软件及灯控线路图教程 一、前言 以下软件程序教程以 佳易王桌球室计时计费软件V17.0为例说明 软件文件下载可以点击最下方官网卡片——软件下载——试用版软件下载 1、每个桌子对应的有 开台时间&#xff0c;所用的时…

python如何模拟登录Github

首先进入github登录页&#xff1a;https://github.com/login 输入账号密码&#xff0c;打开开发者工具&#xff0c;在Network页勾选上Preserve Log&#xff08;显示持续日志&#xff09;&#xff0c;点击登录&#xff0c;查看Session请求&#xff0c;找到其请求的URL与Form Da…

【RL】Monte Carlo Learning(蒙特卡洛学习)

Lecture 5: Monte Carlo Learning The simplest MC-based RL algorithm: MC Basic 理解MC basic算法的关键是理解如何将policy iteration算法迁移到model-free的条件下。 Policy iteration算法在每次迭代过程中有两步&#xff1a; { Policy evaluation: v π k r π k γ…

java之VO,BO,PO,DO,DTO

概念 VO&#xff08;View Object&#xff09;&#xff1a;视图对象&#xff0c;用于展示层&#xff0c;它的作用是把某个指定页面&#xff08;或组件&#xff09;的所有数据封装起来。DTO&#xff08;Data Transfer Object&#xff09;&#xff1a;数据传输对象&#xff0c;这…

VMware虚拟机安装CentOS7

对于系统开发来说&#xff0c;开发者时常会需要涉及到不同的操作系统&#xff0c;比如Windows系统、Mac系统、Linux系统、Chrome OS系统、UNIX操作系统等。由于在同一台计算机上安装多个系统会占据我们大量的存储空间&#xff0c;所以虚拟机概念应运而生。本篇将介绍如何下载安…

趋高技术开发出超低价的视觉尺寸测量仪软件

2024年1月1日元旦节当日&#xff0c;深圳市趋高技术有限公司Fuxi实验室开发组成员成功开发出一款视觉尺寸测量仪软件。这款软件类比市场价格处于超低价。仅报三千二百元。有需要的码农或客户都可以了解一下&#xff0c;带回家。 趋高技术HITREND是深圳的一家高科技公司。 …

Navicat:在 Navicat 中创建外键约束

文章目录 1 表设计2 外键设置3 删除、更新操作设置4 保存 在 Navicat 中&#xff0c;可以在“表设计器”的“外键”选项卡上找到外键约束。 1 表设计 若要创建新的外键约束&#xff0c;请以“表设计器”打开子表&#xff08;在本例中为 fwaq_flow_jcjd&#xff09;&#xff0…

Linux系统的历史记录添加时间和IP信息

1 为什么要优化系统历史记录 对于linux系统&#xff0c;默认情况下&#xff0c;系统记录的历史命令比较简单。某些历史记录可能也无法正常保存&#xff0c;因此当服务器出现异常&#xff0c;希望通过历史命令来了解曾经做了哪些操作时&#xff0c;往往非常被动&#xff0c;下面…

[计算机网络]深度学习传输层TCP协议

&#x1f493; 博客主页&#xff1a;从零开始的-CodeNinja之路 ⏩ 收录专栏&#xff1a;深度学习传输层TCP协议 &#x1f389;欢迎大家点赞&#x1f44d;评论&#x1f4dd;收藏⭐文章 [计算机网络]深度学习传输层TCP协议 前提概括一: TCP协议段格式二:确认应答三:超时重传四:…

vivado RAM HDL Coding Techniques

Vivado synthesis可以解释各种RAM编码风格&#xff0c;并将它们映射到分布式RAM中或块RAM。此操作执行以下操作&#xff1a; •无需手动实例化RAM基元 •节省时间 •保持HDL源代码的可移植性和可扩展性从编码示例下载编码示例文件。 在分布式RAM和专用RAM之间的选择块存储器…

基于SSM的电影购票系统(有报告)。Javaee项目。ssm项目。

演示视频&#xff1a; 基于SSM的电影购票系统&#xff08;有报告&#xff09;。Javaee项目。ssm项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&#xff0c;通过Spring Spri…

十大经典排序算法之一--------------堆排序(java详解)

一.堆排序基本介绍&#xff1a; 堆排序是利用堆这种数据结构而设计的一种排序算法&#xff0c;堆排序是一种选择排序&#xff0c;它的最坏&#xff0c;最好&#xff0c;平均时间复杂度均为O(nlogn)&#xff0c;它也是不稳定排序。堆是具有以下性质的完全二叉树&#xff1a;每个…

内存基础知识

内存作用&#xff1a;用来存放数据 int x10&#xff1b; xx1&#xff1b; 这会生成一个可执行文件&#xff08;装入模块&#xff09;然后存入内存地址中 绝对装入&#xff1a;-如果知道程序放到内存中哪个位置&#xff0c;编译程序将产生绝对地址的目标代码 可重定位装入&am…

idea 打不开项目 白屏

使用IDEA打开项目&#xff0c; 不知名原因崩溃了&#xff0c; 直接出现缩略图白屏。 解决过程&#xff1a; 尝试过重启IDEA&#xff0c;重启过电脑&#xff0c;重新引入相同项目&#xff08;使用不同路径&#xff0c;存在缓存记录&#xff0c;依然打不开&#xff09;&#xff…

数据结构——lesson3单链表介绍及实现

目录 1.什么是链表&#xff1f; 2.链表的分类 &#xff08;1&#xff09;无头单向非循环链表&#xff1a; &#xff08;2&#xff09;带头双向循环链表&#xff1a; 3.单链表的实现 &#xff08;1&#xff09;单链表的定义 &#xff08;2&#xff09;动态创建节点 &#…

删除链表的倒数第N个节点

删除链表的倒数第N个节点 给你一个链表&#xff0c;删除链表的倒数第 n 个结点&#xff0c;并且返回链表的头结点。 进阶&#xff1a;你能尝试使用一趟扫描实现吗&#xff1f; 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5], n 2 输出&#xff1a;[1,2,3,5] 示例…