【C++语言】类和对象--默认成员函数 (中)

在这里插入图片描述


文章目录

  • 前言
  • 类的六个默认成员函数:
    • 1. 构造函数
      • 概念
      • 特性
      • 做了什么?
      • 易错注意:
      • 显式定义和默认构造函数
    • 2. 析构函数
      • 概念
      • 特征
      • 做了什么?
      • 注意事项:
    • 3.拷贝构造函数
      • 概念
      • 特征
      • 做了什么?
      • 注意事项:
    • 4.赋值运算符重载
      • 运算符重载
      • 赋值运算符的重载
      • 注意事项:
    • 5.取地址及const取地址操作符重载
  • 总结
  • C++语言系列学习目录


前言

本节是要学习六个默认成员函数。主要是从四个方面讲解:
1)什么是该默认成员函数?
2)默认成员函数做了什么?
3)一些易错的注意事项
4)什么时候用默认成员函数,什么时候显式实现?
本篇用 日期类(Date)、栈(Stack) 、队列(Queue)三种类来举例


类的六个默认成员函数:

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

1. 构造函数

构造函数就与我们所写的Init()方法一样,用于类对象属性的初始化。但这个构造函数不用用户调用,而是在类对象实例化时自动调用。

概念

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

特性

我们围绕第一个问题展开:什么是构造函数?
其有如下特征:

  1. 函数名与类名相同
  2. 无返回值
class Date
{
public://函数名和类名相同,无返回值Date(int year, int month, int day){_year = year;_month = month;_day = day;}void Print(){cout << _year << "-" << _month << "-" << _day << endl;}
private:int _year;int _month;int _day;
};
  1. 函数可以重载
class Date
{
public://无参数Date(){_year = year;_month = month;_day = day;}/*//全缺省:注意全缺省和无参数不能同时存在,他们实例化方式可以相同,编译器无法辨别Date(int year=2024,int month=4,int day=27){_year = year;_month = month;_day = day;}*///半缺省Date(int year,int month=4,int day=27){_year = year;_month = month;_day = day;}//不缺省Date(int year, int month, int day){_year = year;_month = month;_day = day;}
private:int _year;int _month;int _day;
};
  1. 对象实例化时编译器自动调用
  2. 如果类中没有显式定义构造函数,则C++编译器会自动生成一个无参的默认构造函数,一旦用户显式定义编译器将不再生成。后面实例化对象按照显式定义的函数调用(举例看下面代码注释)

Date类举例:

class Date
{
public:/*// 5.如果用户显式定义了构造函数,编译器将不再生成默认构造函数,后面也不能用Date d1;这样实例化,而是采用Date d1(2024,4,27);这样来实例化对象;Date(int year, int month, int day){_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();return 0;
}

这里我们用Date实例化了个对象d1,调用Print函数打印日期,发现个问题如下图:
在这里插入图片描述
我们发现我们的实例化对象d1并没有初始化啊,那默认构造函数到底干了什么呢?

做了什么?

C++把类型分成内置类型(基本类型)和自定义类型。内置类型就是语言提供的数据类型,如:int/char…,自定义类型就是我们使用class/struct/union等自己定义的类型。默认生成的构造函数对两者处理不同:
1)内置类型不做处理;
2)自定义类型调用它自己的默认构造函数;

易错注意:

  1. 实例化对象,错误:
int main()
{Date d1;     //表示实例化一个Date类对象;Date d1();	 //表示一个返回值为Date的d1()函数方法;return 0;
}
  1. 无参数构造函数、全缺省构造函数、默认构造函数三种都可以当做默认构造函数,只能存在其中一个,不然会发生实例化时编译器不知道调用哪一个构造函数的错误。因为都可以用Date d1;来实例化对象。
  2. C++11 中针对内置类型成员不初始化的缺陷,又打了补丁,即:内置类型成员变量在类中声明时可以给默认值。
class Date
{
public:void Print(){cout << _year << "-" << _month << "-" << _day << endl;}
private://可以在这里给缺省值int _year=2024;int _month=4;int _day=27;
};
int main()
{Date d1;d1.Print();return 0;
}

在这里插入图片描述

显式定义和默认构造函数

那么什么时候我们采用显式定义,什么时候采用默认构造函数呢?
我给出的答案是,一般都自己显式定义比较好。
默认构造函数在以下几种情况下可以使用:

  1. 内置类型成员都具有缺省值(默认值);
  2. 类中全是自定义类型,如:Queue;

2. 析构函数

析构函数是一个特殊的成员函数,其名称与类名相同,前面加上波浪号(~)作为前缀。析构函数的主要作用是执行对象生命周期结束时的清理工作。当一个对象的生命周期结束时,无论是因为超出作用域、被显式删除,还是因为其所在的动态内存分配被释放,析构函数都会被自动调用。

概念

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

特征

那么什么是析构函数呢?
它有以下特征:

  1. 函数名就是在类名前加~;
  2. 无参数、无返回类型;
  3. 一个类只能由一个析构函数。若没有显示定义,系统自动调用默认析构函数。注意:析构函数不能够重载;
  4. 对象生命周期结束时,C++编译系统系统自动调用析构函数。

Stack类 举例:

class Stack {public://构造函数Stack(int capacity=4) {_a = (int*)malloc(sizeof(int) * capacity);if (NULL == _a){perror("malloc fail");return;}_capacity = capacity;_size = 0;}//析构函数:显式定义~Stack(){//释放动态调用的空间资源free(_a);_a = NULL;}private:int* _a;int _size;int _capacity;
};int main()
{{Stack s1(10);}//s1作用域结束自动调用 ~Stack();//不论显示定义,还是默认析构函数,都不需要显示调用;return 0;
}

在这里插入图片描述

做了什么?

默认析构函数做了什么?

  1. 内置类型不做处理;
  2. 自定义类型调用它的析构函数;

内置类型成员,销毁时不需要资源清理,最后系统直接将其内存回收即可

注意事项:

  1. 如果类中没有申请资源时,析构函数可以不写,直接使用编译器生成的默认析构函数,比如Date类;有资源申请时,一定要写,否则会造成资源泄漏,比如Stack类。
  2. Queue类,成员全是自定义类型,会调用成员各自的析构函数。所以不用调用析构函数。
  3. 只有堆上的资源需要手动释放。

3.拷贝构造函数

拷贝构造函数是C++中的一种特殊的构造函数,用于创建一个新对象,该对象是已存在对象的副本。拷贝构造函数在多种情况下会自动被调用。

概念

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

特征

拷贝构造函数有以下特征:

  1. 拷贝构造函数是构造函数的重载形式。
  2. 拷贝构造函数的参数只有一个且必须是类类型对象的引用。
  3. 若未显式定义,编译器会生成默认的拷贝构造函数。 默认的拷贝构造函数对象按内存存储按字节序完成拷贝,这种拷贝叫做浅拷贝,或者值拷贝。

Date类 举例:

class Date
{
public:Date(int year = 1900, 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;//拷贝构造函数Date d2(d1);return 0;
}

做了什么?

默认拷贝构造:依旧是一样的,对内置类型进行浅拷贝,自定义类型调用它们自己的拷贝构造。不需要显示定义的类,比如:Date、Queue。需要显式定义的类,比如:Stack。因为有动态空间的开辟,所以需要深拷贝。

注意事项:

这个比较容易错,大家请注意!

  1. 默认拷贝构造只是浅拷贝,需要深拷贝的对象需要显示定义拷贝构造函数。
    举个Stack的例子:我们如果只是浅拷贝来处理Stack会出现错误。
比如:Stack s2(s1);
如果只是浅拷贝: s2._a=s1._a; 只是这种两个指针指向同一个开辟的空间;
  • 问:这种会出现怎样的问题呢?

  • 答:在函数结束的时候,s1调用一次析构函数,把空间释放了;s2也会在调用一次,此时原本空间已经被释放了,无法再次释放,会报错。

  1. 强调,显示定义拷贝构造函数,只能传一个参数并且必须为该类的引用。不能传值。
    原因:如果进行传值传参,会在过程中调用拷贝构造去拷贝一个data临时对象,用于传值。如下图,便无限的调用下去,没有结束点,进入死循环。所以发生报错。

在这里插入图片描述

4.赋值运算符重载

运算符重载

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

  1. 不能新增加运算符;
  2. 保持运算符具有原有语意;
  3. 不改变运算符原有操作数个数;(比如+,就只能两个对象进行)
  4. 作为类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐藏的this
  5. .* :: sizeof ?: . 注意以上5个运算符不能重载。这个经常在笔试选择题中出现。

赋值运算符的重载

1. 赋值运算符重载格式
参数类型:const T&,传递引用可以提高传参效率
返回值类型:T&,返回引用可以提高返回的效率,有返回值目的是为了支持连续赋值
检测是否自己给自己赋值
返回*this :要复合连续赋值的含义

Date类 举例:

class Date
{
public:Date(int year = 1900, 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;}//赋值运算符重载Date& operator=(const Date& d){if (this != &d){_year = d._year;_month = d._month;_day = d._day;}return *this;}
private:int _year;int _month;int _day;
};int main()
{Date d1(2024,5,5);//拷贝构造函数Date d2(2024,5,6);Date d3;d3 = d1 = d2;return 0;
}

在这里插入图片描述

注意事项:

  1. 赋值运算符重载是默认构造函数,不写,会进行简单的赋值和浅拷贝类似。通常需要为包含动态分配内存的类重载赋值运算符,以执行深拷贝操作。深拷贝意味着为新对象分配新的内存,并复制原对象所指向的内存内容,从而确保两个对象独立拥有自己的内存资源。
  2. 注意区分什么是赋值,什么时候是构造:
Date d1(2024,5,5); //构造
Date d2 = d1;      //构造
Date d3; 
d3=d1;             //赋值
辨别方法:已存在的对象初始化另一个对象叫构造;两个都存在的对象,则是赋值。
//小技巧:看前面有没有Date 类

5.取地址及const取地址操作符重载

这两个默认成员函数一般不用重新定义 ,编译器默认会生成。

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

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


总结

本章节介绍了四个主要的默认成员函数,还有两个不常用就没有过多介绍。


C++语言系列学习目录

提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加,添加超链接

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

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

相关文章

CellMarker | 人骨骼肌组织细胞Marker大全!~(强烈建议火速收藏!)

1写在前面 分享一下最近看到的2篇paper关于骨骼肌组织的细胞Marker&#xff0c;绝对的Atlas级好东西。&#x1f44d; 希望做单细胞的小伙伴觉得有用哦。&#x1f60f; 2常用marker&#xff08;一&#xff09; general_mrkrs <- c( MYH7, TNNT1, TNNT3, MYH1, MYH2, "C…

ComfyUI 基础教程(十三):ComfyUI-Impact-Pack 面部修复

SD的WebUI 中的面部修复神器 ADetailer,无法在ComfyUI 中使用。那么如何在ComfyUI中进行面部处理呢?ComfyUI 中也有几个面部修复功能,比如ComfyUI Impact Pack(FaceDetailer),以及换脸插件Reactor和IPAdapter。 ComfyUI-Impact-Pack 是一个功能强大的插件,专为 ComfyUI …

淘宝扭蛋机小程序开发:开启你的惊喜之旅

一、扭出新世界&#xff0c;惊喜不断 在这个充满无限可能的数字时代&#xff0c;淘宝扭蛋机小程序为你带来了一种全新的购物与娱乐体验。扭蛋机&#xff0c;这个充满童趣和惊喜的玩具&#xff0c;如今在我们的小程序中焕发出新的活力&#xff0c;为你带来一波又一波的惊喜与快…

【CTF Web】XCTF GFSJ0485 simple_php Writeup(代码审计+GET请求+PHP弱类型漏洞)

simple_php 小宁听说php是最好的语言,于是她简单学习之后写了几行php代码。 解法 &#xfeff;<?php show_source(__FILE__); include("config.php"); $a$_GET[a]; $b$_GET[b]; if($a0 and $a){echo $flag1; } if(is_numeric($b)){exit(); } if($b>1234){ech…

jquery项目 html使用export import方式调用模块

jquery的老项目&#xff0c;引入vue3, 需要方便使用export, import方式引用一些常用的方法与常量 导出模块 export js/numberUtil.js /*** Description:* Author Lani* date 2024/1/10*//* * 【金额】 保留2位小数&#xff0c;不四舍五入 * 5.992550 >5.99 , 2 > 2.…

【Kaggle】练习赛《洪水数据集的回归预测》(下)

前言 上篇《洪水数据集的回归预测》(上) 介绍了该数据集非常特殊之处&#xff0c;各特征都非常类似&#xff0c;没有特别之处&#xff0c;各特征之间的相关系数几乎为零。同时&#xff0c;各类模型不敏感&#xff0c;最理想的模型居然是线性回归&#xff0c;决定系数 R 2 R^2 …

64位Office API声明语句第118讲

跟我学VBA&#xff0c;我这里专注VBA, 授人以渔。我98年开始&#xff0c;从源码接触VBA已经20余年了&#xff0c;随着年龄的增长&#xff0c;越来越觉得有必要把这项技能传递给需要这项技术的职场人员。希望职场和数据打交道的朋友&#xff0c;都来学习VBA,利用VBA,起码可以提高…

达梦数据库导入数据问题

进行数据导入的时候遇到了导入数据问题 第一个问题&#xff1a; 该工具不能解析此文件&#xff0c;请使用更高版本的工具 这个是因为版本有点低&#xff0c;需要下载最新的达梦数据库 第二个问题&#xff1a; &#xff08;1&#xff09;本地编码&#xff1a;PG_GBK, 导入文…

全国31省对外开放程度、经济发展水平、ZF干预程度指标数据(2000-2022年)

01、数据介绍 自2000年至2022年&#xff0c;中国的对外开放程度不断深化、经济发展水平不断提高、ZF不断探索并调整自身在经济运行中的角色和定位&#xff0c;以更好地适应国内外环境的变化&#xff0c;也取得了举世瞩目的成就。这一期间&#xff0c;中国积极融入全球经济体系…

[机器学习-02] 数据可视化神器:Matplotlib和Seaborn工具包实战图形大全

目录 引言 正文 01-Matplotlib包的使用示例 1&#xff09;Matplotlib导入方式 2&#xff09;折线图绘制 3&#xff09;散点图绘制 4&#xff09;柱状图绘制 5&#xff09;饼图绘制 6&#xff09;等高线图绘制 7&#xff09;箱线图绘制 8&#xff09;较为复杂…

7zip如何只压缩文件不带上级目录?

在使用7zip进行文件压缩的时候&#xff0c;如果直接选择要压缩的文件进行压缩&#xff0c;得到的压缩包则会多包含一层顶层目录&#xff0c;解压缩之后需要点击两次才能进入到实际目录中&#xff0c;为了解决这个问题&#xff0c;本文根据探索找到了一种解决办法。 如下是一个演…

表空间的概述

目录 表空间的属性 表空间的类型 永久性表空间(PermanentTablespace) 临时表空间(Temp Tablespace ) 撤销表空间(Undo Tablespace) 大文件表空间(BigfileTablespace) 表空间的状态 联机状态(Online) 读写状态(Read Write) 只读状态(Read) 脱机状态(Offline) Oracle从…

Java_从入门到JavaEE_09

一、构造方法/构造器 含义&#xff1a;和new一起是创建对象的功能 特点&#xff1a; 与类名相同的方法没有返回项 注意&#xff1a; 当类中没有写构造方法时&#xff0c;系统会默认添加无参构造&#xff08;无参数的构造方法&#xff09;构造方法可以重载的 有参构造好处&…

透明加密软件选哪个好?选择时一定要注意以下三点

透明加密软件哪个好&#xff1f; 这是许多企事业单位在面临数据防泄漏问题时经常思考的问题。随着信息技术的发展&#xff0c;企业的数据安全变得越来越重要。透明加密技术作为一种有效的数据保护手段&#xff0c;被越来越多的企业所采用。然而&#xff0c;市场上的透明加密软…

Django高级表单处理与验证实战

title: Django高级表单处理与验证实战 date: 2024/5/6 20:47:15 updated: 2024/5/6 20:47:15 categories: 后端开发 tags: Django表单验证逻辑模板渲染安全措施表单测试重定向管理最佳实践 引言&#xff1a; 在Web应用开发中&#xff0c;表单是用户与应用之间进行交互的重要…

OpenHarmony实战开发-请求自绘制内容绘制帧率

对于基于XComponent进行Native开发的业务&#xff0c;可以请求独立的绘制帧率进行内容开发&#xff0c;如游戏、自绘制UI框架对接等场景。 接口说明 开发步骤 说明&#xff1a; 本范例是通过Drawing在Native侧实现图形的绘制&#xff0c;并将其呈现在NativeWindow上 1.定义Ark…

《第一行代码》第二版学习笔记(7)——使用通知和摄像头

文章目录 一、使用通知二、调用摄像头 介绍了通知基于8.0的使用方法和如何调用摄像头拍照 一、使用通知 public void onClick(View v) {if (v.getId() R.id.send_notice){Intent intent new Intent(this,NotificationActivity.class);PendingIntent pi PendingIntent.getAct…

【哈希表】Leetcode 14. 最长公共前缀

题目讲解 14. 最长公共前缀 算法讲解 我们使用当前第一个字符串中的与后面的字符串作比较&#xff0c;如果第一个字符串中的字符没有出现在后面的字符串中&#xff0c;我们就直接返回&#xff1b;反之当容器中的所有字符串都遍历完成&#xff0c;说明所有的字符串都在该位置…

springcloud第4季 springcloud-alibaba之分布式事务seata

一 seata介绍 1.1 seata介绍 1.seata是一款解决分布式事务的解决方案&#xff0c;致力于在微服务架构下提供高性能和简单易用的分布式事务服务。 2.seata的几种术语&#xff1a;一个中心&#xff1a;全局事务id TC(Transaction Coordinator):事务协调者。负责维护全局和分…

通过iMock学习Jvmsandbox

Jvm-sandbox Jvm-sandbox基于Jvm-sandbox的Mock平台iMockiMock的工程学习iMock怎么写的&#xff08;sandbox的module应该怎么写&#xff09; Jvm-sandbox Jvm-sandbox是阿里开源的一款java的沙箱&#xff0c;看网上的介绍在沙箱里你可以做你能想到的奇妙的事情。 基于Jvm-san…