构造函数 | 初始化列表 | 拷贝构造 | 赋值运算符重载

文章目录

        • 1.类的6个默认成员函数
        • 2.构造函数
          • 2.1基本概念和用法
          • 2.2初始化列表
          • 2.3explicit关键字
        • 3.拷贝构造函数
        • 4.重载赋值运算符

1.类的6个默认成员函数

如果定义一个空类,其实并不是什么都没有,编译器会默认生成6个默认的成员函数!默认成员函数,如果用户不显式实现,编译器会生成的成员函数称为默认成员函数

class Date {};

在这里插入图片描述

2.构造函数
2.1基本概念和用法

构造函数:名字与类名相同,无法返回值的特殊成员函数;创建类类型对象时由编译器自动调用,保证每个数据成员都有 一个合适的初始值,并且在对象整个生命周期内只调用一次,构造函数名字听着像是构造对象的,,但是构造函数的主要任务并不是开空间创建对象,而是初始化对象

class student
{
public:student() { cout << "_age value is " << _age << endl;_age = 19;cout << "student()构造函数被调用" << endl; }
private:int _age = 18;	// 不是初始化,注意是_age声明!
};int main()
{// 对象(自定义类型变量)示例化,在栈上开辟空间student stu;return 0;
}

注意:

  1. 构造函数可以被重载,拷贝构造函数和构造函数构成重载
  2. 如果类中没有显式定义构造函数,则C++编译器会自动生成一个无参的默认构造函数,一旦用户显式定义编译器将不再生成。
  3. 编译器默认生成的构造含,C++标准规定:对内置类型(如:整形int double 、任何类型的指针等)不做处理、对自定义类型会调用它的默认构造函数(默认构造函数包括:无参构造函数、全缺省构造函数、我们没写编译器默认生成的构造函数)
  4. C++标准是规定了不做处理,但是标准不是人人都遵守的,VS下有些版本会处理!太狠了!C++11提供了,缺省参数的方式,声明是做了处理,当调用构造函数时会根据缺省值初始化,如:int _age = 18;
class student
{
public:// 注意这里显示写初始化列表就不去走 int _age = 18;这里的缺省了,太坑了!student() :_age(){ cout << "_age value is " << _age << endl;}int _age = 18;
};
int main()
{student stu;return 0;
}
class Date {
private:int _year;int _month;int _day;public:Date(){_year = 10;	_month = 10; _day = 10;}Date(int year = 5, int month = 5, int day = 5){_year = year;_month = month; _day = day;}
};
int main()
{//这里无法通过编译,有两个无参构造函数,产生歧义。(构成重载,但是产生歧义)Date date;return 0;
}
2.2初始化列表
class student
{
public:student() { _age = 19;cout << "student()构造函数被调用" << endl; }
private:int _age = 18;	// 不是初始化,注意是_age声明!
};

这里使用缺省参数int _age = 18;是声明,在student() {_age = 19;}构造函数中,也不能算是真正的初始化,构造函数体中的语句只能将其称为赋初值!因为初始化只能初始化一次,而构造函数体内可以多次赋值

真正初始化的地方在初始化列表:以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个**"成员变量"后面跟一个放在括号(会去调用别人拷贝构造)中的初始值或表达式**。

class student
{
public:student(int age = 18):_age(age){ cout << "_age value is " << _age << endl;}
private:int _age;
};
int main()
{student stu1;student stu2(19);return 0;
}
  • 注意:每个成员变量在初始化列表中只能出现一次(初始化只能初始化一次);尽量优先是初始化列表初始化,对于自定义类型成员变量,一定会先使用初始化列表初始化。

  • 类中包含以下成员,必须放在初始化列表位置进行初始化:1.const成员变量 2.引用成员变量 3.自定义类型成员(且该类没有默认构造函数时)

class A
{
public:A(int a):_a(a){}
private:int _a;
};
class B
{
public:B(int a, int ref):_aobj(a), _ref(ref), _n(10){}
private:A _aobj;		// 没有默认构造函数int& _ref;		// 引用const int _n;	// const 
};int main()
{B b(1, 2);
}
  • 成员变量在类中声明次序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后次序无关
class A
{
public:A(int a):_a1(a), _a2(_a1){}void Print() {	cout << _a1 << " " << _a2 << endl; }
private:int _a2;int _a1;
};
int main() 
{A aa(1);aa.Print();
}

输出结果:

1 -858993460
2.3explicit关键字

构造函数不仅可以构造与初始化对象,对于单个参数或者除第一个参数无默认值其余均有默认值的构造函数,还具有类型转换的作用

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

Date d1 = 2021;隐式类型转换,调用Date(int year, int month = 1, int day = 1);构造函数。

class Date
{
public:explicit Date(int year, int month = 1, int day = 1):_year(year), _month(month), _day(day){}...
};
int main()
{Date d1 = 2021;return 0;
}

在构造函数前加上explicit修饰,不能隐式转换,当然在字符串中,隐式类型转换还是很好的

#include<iostream>
#include<string>	
using namespace std;int main()
{// 1.隐式类型转换string str1 = "hello";// 2.调用构造函数,和上面的等价string str2("hello");return 0;
}
3.拷贝构造函数

拷贝构造函数是构造函数的一个重载形式,拷贝构造函数的参数(显示的,有一个隐藏的this)只有一个必须是类类型对象的引用,使用传值方式编译器直接报错,因为会引发无穷递归调用。

int fun(int num)
{cout << "int fun(int num){}" << endl;return num;
}

上面的的int fun(int num)函数传参和返回值传值返回,会发生两次拷贝,如果我们**显示实现自定义类的拷贝构造函数Date(const Date& date)**会更直观。

class Date
{
public:Date(int year=2023, int month = 1, int day = 1):_year(year), _month(month), _day(day){}Date(const Date& date){_year = date._year;_month = date._month;_day = date._day;}int _year;int _month;int _day;
};Date fun(Date date)
{cout << "Date fun(Date date){}" << endl;return date;
}int main()
{Date d1;fun(d1);
}

通过调试fun(d1);发现会调用两次拷贝构造函数,Date fun(Date date)一次是传参一次是返回这,所以拷贝构造函数不能使用传值的方式Date(Date date)方式,在拷贝构造中重复调用拷贝构造,引发无穷递归,但是不用担心,编译器会制止这样的行为!

Date fun(Date date)做修改:

Date fun(const Date& date)
{cout << "Date fun(Date date){}" << endl;return date;
}

引用做参数,不会调用拷贝构造函数,提高效率,当然在函数体内部修改对象,出了函数作用域,修改的值也存在;但是上面加上了const说明date对象不能修改,但外部的const非const对象都能传递。

4.重载赋值运算符
class Date
{
public:Date(int year=2023, int month = 1, int day = 1):_year(year), _month(month), _day(day){}Date(const Date& date){_year = date._year;_month = date._month;_day = date._day;}Date& operator =(const Date& date){if (this != &date){_year = date._year;_month = date._month;_day = date._day;}return *this;}void print(){std::cout << _year << "-" << _month << "-" << _day << std::endl;}
private:int _year;int _month;int _day;
};int main()
{Date d1(2024, 2, 1);Date d2 = d1;Date d3;d3 = d1;d2.print();d3.print();
}

上面是正确的写法,另外注意:Date d2 = d1;这里连续的构造和赋值拷贝,我在VS2022编译器下,优化成了一次拷贝构造。

为什么Date& operator =(const Date& date)的返回值是Date&,那void和Date能不能行

class
{...void operator =(const Date& date){if (this != &date){_year = date._year;_month = date._month;_day = date._day;}}...
}int main()
{Date d1(2024, 2, 1);Date d2;Date d3;d2 = d1;d3 = d2 = d1;return 0;
}

这行d3 = d2 = d1;是用void返回值不能连续的赋值!那使用Date会怎么样:

class
{...Date operator =(const Date& date){if (this != &date){_year = date._year;_month = date._month;_day = date._day;}return *this;}...
}int main()
{Date d1(2024, 2, 1);Date d2(2021, 2, 1);Date d3;(d3 = d2) = d1;d2.print();d3.print();return 0;
}

输出结果:

2021-2-1
2021-2-1

结果不是我想要的啊!此时由于括号"()"改变了结合顺序,先执行d3=d2,结果是将d2的值赋值给d3,这里是没有问题的!其实d3 = d2 等价于 d3.operator=(d2)函数返回值如果是非引用返回的右值,引用返回的是左值;这里Date operator =(const Date& date)非引用返回右值,但是右值充当左值,出现异常!

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

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

相关文章

从源代码看Chrome 版本号

一直以来都是用Chrome 浏览器&#xff0c;但是看到Chrome 点分4 组数据的表达方式&#xff0c;总是感觉怪怪的&#xff0c;遂深入源代码了解她的版本号具体表示的内容 chrome 浏览器中显示的版本号 源代码中的版本号标识 版本号文件位于 chrome/VERSION &#xff0c; 看到源代…

网络流数据集处理(深度学习数据处理基础)

一、数据集处理 处理数据集是一个文件夹 一个文件夹处理的&#xff0c;将原网络流数据集 放入一个文件夹 处理转换成 Json文件。&#xff08;数据预处理&#xff09;然后将这些文件处理成目标文件格式 再分割成训练集和测试集。每次运行只会处理一个文件夹。 运行train.py 导入…

Unity_PackageManager缺失

Unity_PackageManager缺失 Unity早期版本不带PakageManager&#xff0c;或是人为因素造成PakageManager缺失。 关闭Unity工程&#xff0c;在项目文件下Packages文件夹里打开manifest.json&#xff0c;修改添加一行&#xff1a; "com.unity.package-manager-ui": &q…

Windows10 安装 OpenSSH 配置 SFTP服务器

1、下载 https://github.com/PowerShell/Win32-OpenSSH/releases 2、默认安装 3、创建用户 4、修改配置文件 C:\ProgramData\ssh\sshd_config# 最后一行后面加入 ForceCommand internal-sftp# 设置用户登录后默认目录 Match User sftpuser ChrootDirectory C:\SFTP# Disable…

进程信号-

一.信号概念 信号是进程之间事件异步通知的一种方式&#xff0c;属于软中断。 二.信号的产生 1.通过键盘进行信号的产生。&#xff08;1-31多数都是杀掉进程&#xff09; &#xff08;ctrl c&#xff1a;向前台进程发送2号信号&#xff0c;杀掉进程&#xff09; &#xff0…

基于JAVA的宠物管理系统

技术架构&#xff1a; Servlet JSP MySQL 有需要该项目的小伙伴可以私信我你的Q。 功能介绍&#xff1a; 系统主要分为前台和后台两大模块 前台主要由用户体验使用: 用户登录 注册 查找商品 商品类别等功能导航&#xff1b; 后台…

基于 Echarts 的 Python 图表库:Pyecahrts交互式的K线图(股票)

目录 一、K线图的介绍 二、K线图的使用场景 1. 趋势分析 2. 支撑与阻力 3. 价格反转 4. 交易信号 5. 波动性分析 三、Pyecharts绘制K线图 四、总结 一、K线图的介绍 K线图&#xff08;K-Line Chart&#xff09;是用于显示金融市场价格走势的一种图表形式&#xff0c;主…

Github 2024-02-03 开源项目日报 Top10

根据Github Trendings的统计&#xff0c;今日(2024-02-03统计)共有10个项目上榜。根据开发语言中项目的数量&#xff0c;汇总情况如下&#xff1a; 开发语言项目数量Python项目6C项目1TypeScript项目1JavaScript项目1PowerShell项目1Rust项目1 MLflow: 机器学习生命周期平台 …

代码随想录day14 Java版 二叉树部分

今天开始刷二叉树的题目&#xff0c;发现大多数都是在昨天的遍历的基础上的变式 226.翻转二叉树 根据题目描述模拟整个交换过程&#xff0c;发现非常像前序遍历的递归方式&#xff1a;每次先将当前节点的左右孩子互换&#xff0c;再递归左右孩子&#xff0c;当节点为空的时候…

Codeforces Round 734 (Div. 3)B2. Wonderful Coloring - 2(贪心构造实现)

思路&#xff1a; 分类讨论&#xff1a; 当一个数字出现的次数大于等于k&#xff0c;那么最多有k个能被染色&#xff0c; 当一个数字出现的次数小于k&#xff0c;南那么这些数字都可能被染色 还有一个条件就是需要满足每个颜色的数字个数一样多&#xff0c;这里记出现次数小于k…

C#学习笔记_继承

基本概念 继承是面向对象程序设计中最重要的概念之一。继承允许我们根据一个类来定义另一个类&#xff0c;这使得创建和维护应用程序变得更容易。同时也有利于重用代码和节省开发时间。 当创建一个类时&#xff0c;程序员不需要完全重新编写新的数据成员和成员函数&#xff0…

AI监控+智能充电桩系统如何缓解新能源汽车充电难问题

在新能源汽车行业的快速发展中&#xff0c;充电桩作为重要的配套设施&#xff0c;其建设和发展至关重要。随着新能源汽车销量的增长&#xff0c;补能需求也日益迫切&#xff0c;这为充电桩行业的发展提供了巨大的机遇。然而&#xff0c;充电桩行业在快速发展的同时&#xff0c;…

MavenGradle等引入jSerialComm

引入 jSerialComm [2.0.0,3.0.0) 此版本发布于 Nov 7, 2023 (23年11月) Maven: <dependency><groupId>com.fazecast</groupId><artifactId>jSerialComm</artifactId><version>[2.0.0,3.0.0)</version> </dependency>Ivy: …

[云顶数模]2024美赛CEF题成品参考论文+配套数据集+可执行代码+运行结果图

E题社区抗灾能力综合评估与决策模型研究 摘要&#xff1a;社区抗灾能力的提升对于灾害风险管理至关重要。本研究基于机器学 习方法&#xff0c;构建了社区抗灾能力预测模型&#xff0c;以评估社区在灾害事件中的表现。首先&#xff0c; 我们采用梯度提升树模型对社区基础设施、…

Prometheus 采集Oracle监控数据

前言 oracledb_exporter是一个开源的Prometheus Exporter,用于从Oracle数据库中收集关键指标并将其暴露给Prometheus进行监控和告警。它可以将Oracle数据库的性能指标转换为Prometheus所需的格式,并提供一些默认的查询和指标。 download Oracle Oracle Windows Install …

C++面试:事务的隔离级别和实践原理

目录 1. 读未提交&#xff08;Read Uncommitted&#xff09; 定义 问题 场景 实践注意事项 MySQL SQL Server PostgreSQL 注意 2. 读提交&#xff08;Read Committed&#xff09; 定义 问题 场景 如何操作 MySQL SQL Server PostgreSQL 注意事项 3. 可重复读…

【Docker】网络配置network详解

一&#xff0c;network的概述 解决痛点&#xff08;能干什么&#xff1f;&#xff09;&#xff1a; &#xff08;1&#xff09;容器间的互联和通信以及端口映射 &#xff08;2&#xff09;容器IP变动时候&#xff0c;可以通过服务名直接网络通信而不受到影响 二&#xff0c;n…

webrtc mediasoup sctp 起什么作用? 用来传输什么数据

WebRTC是一种用于实时通信的开放标准&#xff0c;而mediasoup是一个基于WebRTC的流媒体服务器。SCTP&#xff08;Stream Control Transmission Protocol&#xff09;是WebRTC中的一个传输协议&#xff0c;它在WebRTC中起到了重要的作用。 SCTP主要用于在WebRTC中传输数据通道&…

功率信号的频谱

目录 1. 前言2. 功率信号的频谱3. 参考资料 1. 前言 知识点1&#xff1a;函数周期性判定定理   假设函数 f ( x ) f(x) f(x) 和函数 g ( x ) g(x) g(x) 均为周期性函数&#xff0c;其最小正周期分别为 T f T_f Tf​ 和 T g T_g Tg​&#xff0c;若 T f / T g T_f/T_g T…

搜索引擎评价指标及指标间的关系

目录 二分类模型的评价指标准确率(Accuracy,ACC)精确率(Precision,P)——预测为正的样本召回率(Recall,R)——正样本注意事项 P和R的关系——成反比F值F1值F值和F1值的关系 ROC&#xff08;Receiver Operating Characteristic&#xff09;——衡量分类器性能的工具AUC&#xff…