类的六个构造函数相关干货

构造函数

特点

1.名字与类名相同
2.无返回值
3.对象实例化的时候编译器自动调用这个函数
4.构造函数可以重载(无参构造函数,拷贝构造等)
5.如果类中没有显式定义构造函数(深拷贝),则编译器会自动生成一个默认构造函数(浅拷贝/值拷贝),若显式定义了编译器就不再生成

class Date
{
public:Date()//无参构造函数{}Date(int year, int month, int day){_year = year;_month = month;_day = day;}
private:int _year;int _month;int _day;
public:void test1(){Date d1;//无参Date d2(2024, 4, 14);//带参}
};

6.c++把类型分为内置类型和自定义类型,对于内置类型来说,编译器自动生成的默认构造函数是不会将内置类型初始化的(为了弥补这个缺陷,c++11中的内置成员变量在声明的时候是可以给默认值的),所以如果下面这个代码我们没有主动去设置构造函数,里面的三个成员变量就都是随机值,若他是自定义类型,编译器就会去调用这个类型的默认构造函数

#include<iostream>
using namespace std;
class Day
{
public:Day(){_day = 0;cout << "Day()" << endl;}
private:int _day;
};
class Date
{
private:int _year=2024;int _month=4;Day _day;
};
int main()
{Date d1;return 0;
}

7.无参的构造函数,全缺省的构造函数和编译器自动生成的构造函数都可以被称为默认构造函数

初始化列表

来由

调用构造函数赋值时,我们会给变量一个初始值,但是这不能称为变量的初始化,只能称为赋值,因为初始化只能初始化一次,而构造函数中可以对变量多次赋值,于是就产生了初始化列表。

用法

以一个冒号为开始,每个成员变量后面跟着一个用括号隔开的值或者表达式

class vientiane
{
public:vientiane(int year,int month,int day):_year(year),_month(month),_day(day){}
private:int _year;int _month;int _day;
}

注意:每个成员变量在初始化列表中只能初始化一次,也就是只能出现一次,当类中成员变量包含引用成员变量,const类型成员变量,没有默认构造函数的类类型成员变量时,都要放在初始化列表初始化,我们也尽量使用初始化列表初始化,因为不管你用不用初始化列表,程序都会先走初始化列表再执行构造函数里面的内容的,成员变量的声明顺序就是初始化列表的初始化顺序,与初始化列表里的顺序是无关的,所以最好不要让初始化的成员互相初始化,很容易得到随机值

explicit关键字

我们偶尔会看到如下代码

class vientiane
{
public:vientiane(int year,int month=1,int day=1):_year(year),_month(month),_day(day){}
private:int _year;int _month;int _day;
}
int main()
{vientiane d1(2024);vientiane d2=2024;return 0;
}

也许你会疑惑,d2是一个自定义类型,而2024是一个整形,为什么可以这样直接赋值呢?其实,c++里有一种隐式类型转换,比如说你现在有一个整形变量a=1,你想让他赋值给double类型变量b,那么在赋值过程中会产生一个double类型的临时变量,这个double类型的临时变量被赋值成1.0,然后再用这个临时变量去给b赋值,上图那段代码也一样,“2024”会先调用构造函数构造一个vientiane类型的变量,然后再用拷贝构造去初始化d2,如果你不想要有这样的类型转换,你可以在构造函数前加一个explicit关键字

class vientiane
{
public:explicit vientiane(int year,int month=1,int day=1):_year(year),_month(month),_day(day){}
private:int _year;int _month;int _day;
}
int main()
{vientiane d1(2024);vientiane d2=2024;return 0;
}

这样,上述代码就会报错了
在这里插入图片描述

析构函数

概念

析构函数不是对对象的销毁,而是完成销毁后对对象里的资源清理工作,对象的销毁是由编译器自己进行的

特点

1.析构函数名是类名前加一个~
2.析构函数没有参数也没有返回值,自然就无法构成重载
3.一个类只能有一个析构函数,若没有显式定义析构函数,则编译器会自动生成默认析构函数
4.对象生命周期结束时,编译器会自动调用析构函数

#include<iostream>
using namespace std;
class Date
{
public:Date(){_year = 2024;_month = 4;_day = 14;}~Date(){_year = 0;_month = 0;_day = 0;}
private:int _year;int _month;int _day;
};
int main()
{Date d1;return 0;
}

5.编译器生成的默认析构函数和默认构造函数一样,对于自定义类型,编译器都会自动调用对应的默认析构函数
6.如果类中没有申请资源时,析构函数可以不写,但如果有申请时,就必须写析构函数,否则就会造成内存泄露

拷贝构造

概念

只有单个形参,编译器在创建新对象的时候会自动调用,这个形参必须是和新生成对象一样的类型

特点

1.拷贝构造是构造函数的一个重载函数
2.在调用拷贝构造创建新变量的时候,必须使用引用,否则会引发无穷递归调用,因为函数在传参的时候会调用拷贝构造创建形参,所以会无穷尽递归
3.若未显式定义,编译器会生成默认拷贝函数,默认构造函数会按内存储存字节进行字节序拷贝,这种拷贝称为浅拷贝/值拷贝,这种方式有一个缺点,比如说当你初始化一个字符串s1,然后初始化一个s2,如果你执行s1=s2这个操作,那当你改变s1里元素的时候,s2里元素也会跟着改变,这还有一个问题,因为类是有析构函数的,当你程序结束的时候,这个位置会被析构两次,程序就崩了
4.编译器自动生成的默认拷贝构造函数中,内置类型是使用字节拷贝构造的,而自定义类型是调用自定义类型的拷贝构造函数进行拷贝

//拷贝构造
string(const string& str):_size(strlen(str._str)),_str(new char[1])
{delete[] _str;_capacity = _size;char* tmp = new char[_capacity + 1];strcpy(tmp, str._str);_str = tmp;
}

若没有这个自定义函数,两个不同对象的_str会指向同一块空间,动其中一个对象就会影响到另外一个对象。
5.关于什么时候需要写拷贝构造:如果涉及到资源的申请就需要写拷贝构造函数进行深拷贝,否则只需要用编译器自动生成的浅拷贝即可。

应用场景

1.使用已创建对象初始化新对象

string str1;//旧对象
string str2(str1);

2.函数参数类型为类类型对象

void Func(string str);//会调用拷贝构造

3.函数返回值类型为类类型对象

string func()
{string str;return str;
}

注:为了提高传参效率,能传引用就尽量不要用传值调用。

运算符重载

特点

用法

函数名字:operator后接需要重载的运算符符号
函数原型:返回值 operator 需要重载的运算符符号(参数列表)
下图用日期类Date作为例子

ostream& operator<<(ostream& out,Date& d1)
{out<<d1.year<<d1.month<<d1.day<<endl;return out;
}
注意

1.重载操作数必须有一个类类型参数
2.内置类型的运算符不能改变其含义,比如说内置类型的加减乘除,不能通过运算符重载改变它们的含义
3.作为类类型成员重载时,参数少1,有一个参数是隐藏的this指针
4.“*”“::”“sizeof”“?:”“.”这五个运算符不能重载
5.赋值运算符必须重载为类的函数,不能放在全局变量里

Date& operator=(Date& d1,Date& d2)
{if(&d1!=&d2){d1.year=d2.year;d1.month=d2.month;d1.day=d2.day;}return d1;
}

若你去测试这一行代码,你会发现vs编译器底下会报一个错: error C2801: “operator =”必须是非静态成员,原因是用户如果在类中没有显式实现一个赋值运算符重载,编译器会默认生成一个浅拷贝赋值运算符重载,这时如果用户在类外又实现一个运算符重载,就会与编译器中默认生成的函数冲突,所以赋值运算符只能是类内的函数。
6.如果没有涉及到资源拷贝,那么赋值运算符实现和不实现都可以,但一旦涉及到资源申请,就必须实现赋值运算符重载,否则会导致某一些指针指向同一块空间,这个时候当你操作其中一个对象就会影响到另外一个对象,而且有析构两次的问题(一个类里面的成员有包含别的类,没有进行深拷贝就会析构两次,造成程序崩溃)
7.前置++,–与后置++,–的问题:因为前置++和后置++运算符都一样,只是使用的位置不一样,为了区分这两种,c++规定前置++可以和平常的运算符重载一样使用,而若要实现后置++的运算符重载,就需要在参数列表里加一个int

Date operator++();//前置++
Date operator++(int)//后置++

const成员

概念

const修饰的成员函数统称为const成员函数,const修饰成员函数,实际上是修饰该成员函数的隐藏this指针,表明在该成员函数中不能对类的任何成员进行修改

class Date
{
public:void Print() const//等价于 void Print(const Date* this){cout<<_year<<"-"<<_month<<"-"<<_day<<endl;}
private:int _year;int _month;int _day;
}
特点

const成员函数可以调用const成员函数,但不能调用非const成员函数(读写权限被放大),而非const成员函数可以调用const成员函数和非const成员函数
const对象不能调用非const成员函数(读写权限放大),而非const对象两种都可以调用。

取地址运算符重载

一般不自己实现,编译器会自动实现,下图是日期类的一部分

Date* operator&()
{return this;
}
const Date* operator&() const
{return this;
}

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

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

相关文章

抖音阳哥:选品师项目究竟能不能算蓝海项目?

在当今这个信息爆炸的时代&#xff0c;短视频平台如抖音已经成为了人们获取信息、娱乐休闲的重要渠道。抖音上涌现出许多具有影响力的网红&#xff0c;他们不仅分享自己的生活点滴&#xff0c;还常常推荐一些创业项目或商业模式。其中&#xff0c;阳哥分享的选品师项目引起了广…

STM32H750片外QSPI下载算法文件(stldr)生成

STM32H750片外QSPI下载算法文件&#xff08;stldr&#xff09;生成 &#x1f33f;相关篇《STM32H750片外QSPI启动配置简要》&#x1f4cc;参考实现资料&#xff1a; https://github.com/lchnu/STM32H750XBH_ARTPIQSPI_W25Q64JV https://gitee.com/wangchief/H750_W25QXX ✨利…

风格迁移adaIN 和iT的adaLN

文章目录 BN、LN、IN、GN的区别![](https://img-blog.csdnimg.cn/direct/d38c005616f145cba2aa1c4c2e046be0.png)图像风格迁移adaINDiT adaLN BN、LN、IN、GN的区别 BatchNorm&#xff1a;batch方向做归一化&#xff0c;算NxHxW的均值&#xff0c;对小batchsize效果不好&#x…

「Kafka」Kafka基础知识入门介绍(三)

「Kafka」Kafka基础知识入门介绍&#xff08;三&#xff09; 一、消息主题1. 创建主题 二、生产数据1. 命令行模式2. Java代码模式 三、消费数据1. 命令行模式2. Java代码模式 「Kafka」Kafka理论知识解读&#xff08;一&#xff09; 「Kafka」Kafka安装和启动&#xff08;二&a…

【kotlin】利用by关键字更加方便地实现装饰器模式

关于kotlin中的by关键字的用法&#xff0c;kotlin官方文档属性委托这一节讲得很清楚。 简单来说就是这样的&#xff0c;假设存在一个接口Component如下&#xff1a; interface Component {fun method1(): IntArrayfun method2(a: Int)fun method3(a: Int, str: String) }那么对…

React-性能优化的手段

​&#x1f308;个人主页&#xff1a;前端青山 &#x1f525;系列专栏&#xff1a;React篇 &#x1f516;人终将被年少不可得之物困其一生 依旧青山,本期给大家带来React篇专栏内容:React-性能优化的手段 目录 React 性能优化的手段有哪些&#xff1f; 一、是什么 二、如何做…

【汇编语言】流程转移和子程序

【汇编语言】流程转移和子程序 文章目录 【汇编语言】流程转移和子程序前言一、“转移”综述二、操作符offset三、jmp指令jmp指令——无条件转移jmp指令&#xff1a;依据位移进行转移两种段内转移远转移&#xff1a;jmp far ptr 标号转移地址在寄存器中的jmp指令转移地址在内存…

Vue3种常用插槽的使用

插槽总结 &#xff1a; 插槽的作用&#xff1a;让父组件可以向子组件指定位置插入html结构&#xff0c;也是一种组件间通信的方式&#xff0c;适用于 父组件 > 子组件 。分类&#xff1a;默认插槽、具名插槽、作用域插槽 1、默认插槽 父组件中&#xff1a; <Category>…

鸿蒙HarmonyOS应用 - ArkUI组件

ArkUI组件 基础组件 Image 声明Image组件并设置图片源 网络权限&#xff1a;ohos.permission.INTERNET Image(scr: string | PixelMap | Resource)// 1. string&#xff1a;用于加载网络图片&#xff0c;需要申请网络权限 Image("https://xxx.png")// 2. PixelMap…

一线实战,一次底层超融合故障导致的Oracle异常恢复

背景概述 某客户数据由于底层超融合故障导致数据库产生有大量的坏块&#xff0c;最终导致数据库宕机&#xff0c;通过数据抢救&#xff0c;恢复了全部的数据。下面是详细的故障分析诊断过程&#xff0c;以及详细的解决方案描述&#xff1a; 故障现象 数据库宕机之后&#xff0c…

粤嵌—2024/4/24—删除有序数组中的重复项 ||

代码实现&#xff1a; 方法一&#xff1a;双指针 int removeDuplicates(int *nums, int numsSize) {int l 0, r 0;while (r < numsSize) {if (r > 1 && nums[r] nums[l - 1] && nums[r] nums[l - 2]) {r;} else {nums[l] nums[r];l;r;}}return l; }…

ONES 功能上新|ONES Wiki 新功能一览

支持在 ONES Wiki 页面中使用分栏进行横向排版&#xff0c;丰富排版方式&#xff0c;帮助用户以更丰富的版式展示内容。 应用场景&#xff1a; 页面的布局对内容的阅读有很大的影响。当页面中有图文混排的需求时&#xff0c;可以通过分栏来组织页面结构&#xff0c;以更清晰、更…

Docker容器概念介绍与基本管理

前言 在软件开发和部署环境中&#xff0c;使用 Docker 等容器技术可以帮助团队实现快速、一致、可靠的应用程序部署&#xff0c;提高开发效率和应用程序的可移植性。 目录 一、虚拟化产品介绍 1. 云服务模型 1.1 IaaS 1.2 PaaS 1.3 SaaS 1.4 DaaS 2. 产品介绍 2.1 虚…

14 JavaScript学习:条件语句

JavaScript条件语句 JavaScript中的条件语句主要用于根据条件执行不同的代码块。以下是对JavaScript条件语句概念的详细解释和分类&#xff1a; if语句&#xff1a; 单个if语句&#xff1a;最简单的条件语句&#xff0c;根据条件判断是否执行特定的代码块。if…else语句&#x…

【机器学习与实现】机器学习概述

目录 一、机器学习的基本概念和方法&#xff08;一&#xff09;基本概念&#xff08;二&#xff09;机器学习的一般过程举例&#xff08;三&#xff09;样本和参数估计 二、机器学习的步骤总结&#xff08;一&#xff09;机器学习的主要步骤&#xff08;二&#xff09;样本及样…

C++并发编程

基本介绍 线程 C98标准没有直接提供原生的多线程支持 在C98中&#xff0c;并没有像后来的C11标准中那样的<thread>库或其他直接的多线程工具 然而&#xff0c;这并不意味着在C98中无法实现多线程。开发者通常会使用平台特定的API&#xff08;如Windows的线程API或POSI…

vue3中的ref、isRef、shallowRef、triggerRef和customRef

1.ref 接受一个参数值并返回一个响应式且可改变的 ref 对象。 ref 对象拥有一个指向内部值的单一属性 .value property &#xff0c;指向内部值。 例&#xff1a;此时&#xff0c;页面上的 str1 也跟着变化 <template><div><button click"handleClick&quo…

严厉打击侵犯知识产权行为!法院公开审理假冒半岛超声炮知产刑事案件

随着医美行业的蓬勃发展&#xff0c;一些不法分子利用消费者对变美的渴望&#xff0c;制售假冒半岛超声炮&#xff0c;严重侵犯了消费者的合法权益&#xff0c;也破坏了医美市场的健康发展。为了维护市场秩序&#xff0c;保障消费者权益&#xff0c;各地相关监管部门持续加大监…

QT从入门到实战x篇_22_番外1_Qt事件系统

文章目录 1. Qt事件系统简介1.1 事件的来源和传递1.2 事件循环和事件分发1.2.1 QT消息/事件循环机制1.2.1.1 机制解释1.2.1.2 两个问题 1.2.2 事件分发 2. 事件过滤基础2.1 什么是事件过滤器&#xff08;Event Filter&#xff09;&#xff1f;2.2 如何安装事件过滤器 3. 事件过…

<计算机网络自顶向下> 路由器组成

路由器结构概况 路由&#xff1a;运行路由选择算法/协议&#xff08;RIP, OSPF, BGP&#xff09;生成路由表转发&#xff1a;从输入到输出链路交换数据包-根据路由表进行分组的转发中间的fabric是用来接收输入的分组交给输出端口的&#xff0c;完成局部的转发&#xff08;根据…