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

文章目录

        • 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 导入…

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; 后台…

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

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

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

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

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

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

Prometheus 采集Oracle监控数据

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

【Docker】网络配置network详解

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

功率信号的频谱

目录 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…

基于Java SSM框架实现校园兼职系统项目【项目源码+论文说明】

基于java的SSM框架实现校园兼职系统演示 摘要 社会的发展和科学技术的进步&#xff0c;互联网技术越来越受欢迎。网络计算机的生活方式逐渐受到广大人民群众的喜爱&#xff0c;也逐渐进入了每个学生的使用。互联网具有便利性&#xff0c;速度快&#xff0c;效率高&#xff0c;…

[office] excel计算客户名单的人数 COUNTA 函数:“销售额”不仅是金额的总和 #知识分享#职场发展#知识分享

excel计算客户名单的人数 COUNTA 函数&#xff1a;“销售额”不仅是金额的总和 前文中介绍的 SUM 函数&#xff0c;是在日常工作中使用频率最高的函数之一。但是&#xff0c;在实际操作时也会出现问题。比如在计算销售额总和时&#xff0c;SUM 函数得出的结果为金额总和。但是…

RISC-V指令格式

RISC-V指令格式 1 RISC-V指令集命名规范2 RISC-V指令集组成2.1 基础整数指令集2.2 扩展指令集 3 RISC-V指令格式3.1 指令表述3.2 指令格式 本文属于《 RISC-V指令集基础系列教程》之一&#xff0c;欢迎查看其它文章。 1 RISC-V指令集命名规范 前面提到过RV32I&#xff0c;这是…

5. 基础网络服务与应用配置

5.1 实验一&#xff1a;FTP 基础配置实验 5.1.1 实验介绍 5.1.1.1 关于本实验 设备支持多种文件管理方式&#xff0c;用户根据任务和安全性要求选择合适的文件管理方式。 用户可以通过直接登录系统、FTP&#xff08;File Transfer Protocol&#xff09;、TFTP&#xff08;T…

【深度学习】数据归一化/标准化 Normalization/Standardization

目录 一、实际问题 二、归一化 Normalization 三、归一化的类型 1. Min-max normalization (Rescaling) 2. Mean normalization 3.Z-score normalization (Standardization) 4.非线性归一化 4-1 对数归一化 4-2 反正切函数归一化 4-3 小数定标标准化&#xff08;Demi…

Day17、18、19学习记录

#c语言知识 内存管理 1.作用域 &#xff08;1&#xff09;代码块作用域&#xff08;代码块是{}之间的一段代码&#xff09; &#xff08;2&#xff09;函数作用域 &#xff08;3&#xff09;文件作用域 2.局部变量&#xff08;自动变量auto&#xff09;&#xff1a; 在函…

jmeter-03界面介绍

文章目录 主界面介绍测试计划介绍线程组介绍线程组——选择测试计划&#xff0c;右键-->添加-->线程-->线程组 主界面介绍 测试计划介绍 测试计划&#xff1a;本次测试所需要的所有内容&#xff0c;即父线程 线程组介绍 jmeter讲究一个概念&#xff1a;一个线程一…

Linux内存管理:(十一)页面分配之慢速路径

文章说明&#xff1a; Linux内核版本&#xff1a;5.0 架构&#xff1a;ARM64 参考资料及图片来源&#xff1a;《奔跑吧Linux内核》 Linux 5.0内核源码注释仓库地址&#xff1a; zhangzihengya/LinuxSourceCode_v5.0_study (github.com) 1. 水位管理和分配优先级 页面分配…