C++类的多种构造函数

news2024/9/21 8:03:22

目录

    • 默认构造函数
    • 普通构造函数
    • 拷贝构造函数
    • 转换构造函数
    • 移动构造函数
      • 举例两个场景

下面以Complex 复数类来学习C++类中的各种构造函数;

#include <iostream>
using namespace std;

//复数类
class Complex{
      friend ostream & operator<<(ostream &out, Complex &c);  //友元函数
public:
    Complex(){}  //默认构造函数
    
    Complex(double real, double imag): m_real(real), m_imag(imag){ }  //普通构造函数(可以加缺省值)
	
	Complex(const Complex &c):m_real(c.m_real),m_imag(c.m_imag) { } //拷贝构造函数(参数是const Complex &类型)
    
    Complex(double real):m_real(real), m_imag(0.0) { }  //转换构造函数 

	Complex(Complex &&c):m_real(c.m_real),m_imag(c.m_imag) { }  //移动构造函数 
  
private:
    double m_real;  //实部
    double m_imag;  //虚部
};

//重载<<运算符
ostream & operator<<(ostream &out, Complex &c){
    out << c.m_real <<" + "<< c.m_imag <<"i";;
    return out;
}

int main(){
    Complex a(10.0, 20.0);  //调用普通构造函数
    Complex b(89.5);  //调用转换构造函数
    Complex c;  //调用默认构造函数

    return 0;
    }

默认构造函数

  • 未显式提供初始值时,用来创建对象的构造函数;
Complex(){} //默认构造函数

如果该类采用了继承或者定义了虚函数或者成员由非内置类型,那么系统在我们没有定制写出该函数的时候,会自动生成默认构造函数;


普通构造函数

 Complex(double real, double imag);  //普通构造函数(可以带上缺省参数方便初始化!)

用户可以传参与对应普通构造函数进行匹配来构造对象;


拷贝构造函数

拷贝构造 也叫 复制构造

Complex(const Complex &c); //拷贝构造函数(参数是const Complex &类型)

调用场景:

Complex a(1.1,2.2);//用户调用普通构造函数初始化a对象

Complex b(a); //此时b调用拷贝构造函数,用a对象进行拷贝 
Complex b = a;  //等价与上面的Complex b(a);

//下面两条语句不会调拷贝构造,因为c1,c2已经通过默认构造初始化了,再进行=只是调用了operator=(const Complex& src)赋值语句
Complex c1, c2;
c1=c2;

注意,拷贝构造函数与默认构造函数类似,系统一定条件下会自动生成;

(但是系统默认生成的拷贝构造是浅拷贝,遇到了某些自定义类型是很危险的!eg:string 内部有堆地址char*的浅拷贝问题)

拷贝构造参数是const 类型名 &a 的原因是:

  1. **&**避免了传参时候,需要多拷贝一次的开销
  2. 不加**&**会产生“拷贝时需要传参,传参又是一次拷贝的套娃行为”
  3. 用a对象拷贝构造的时候,const防止在函数内部拷贝a时,不小心把a本体给改了;

转换构造函数

  • C++ 允许我们自定义类型转换规则,用户可以将其它类型转换为当前类类型。这种自定义的类型转换规则只能以类的成员函数的形式出现,换句话说,这种转换规则只适用于类。

调用场景:

  • 直接一个=,将等号右边的其它类型转换为当前类类型
  • or(类型)强转时调用转换构造函数(有点C语言隐式类型转换的意思)
Complex(double real):m_real(real), m_imag(0.0) { }  //转换构造函数 

调用场景1:

 Complex a(1.1,2.2);//先用普通构造初始化a对象;
cout<<a<<endl; //输出1.1 + 2.2i

 a = 3.14; //double转Complex,调用转换构造,将double 3.14直接转换为了Complex类型: a(3.14,0.0)  ; 有点像C的隐式类型转换 int a = 3.14这种操作
cout<<a<<endl; //输出3.14 + 0.0i

调用场景2(本质上等价于场景1):

 Complex a = (Complex)25.5;;//C语言的强转;

如果Complex类没有写对应double类型的转换构造函数:Complex(double a),那编译器因为没有转换规则,上述两个场景就会报错,转换失败!


移动构造函数

Complex(Complex &&c) { }  //移动构造函数格式(参数是一个右值 or 将亡值)

先了解一下移动语义: 右值引用和移动语义参考博客

所谓移动语义,指的就是以移动而非深拷贝的方式初始化含有指针成员的类对象

简单的理解,移动语义指的就是将其他对象(通常是临时对象(将亡值))拥有的内存资源“移为已用”。

事实上,对于程序执行过程中产生的临时对象,往往只用于传递数据(没有其它的用处),并且会很快会被销毁。因此在使用临时对象初始化新对象时,我们可以将其包含的指针成员指向的内存资源直接转移给新对象所有无需再新拷贝一份,这大大提高了初始化的执行效率

移动构造函数的参数和拷贝构造函数不同,拷贝构造函数的参数是一个左值引用,但是移动构造函数的参数是一个右值引用

当类中同时包含拷贝构造函数和移动构造函数时,如果使用临时对象初始化当前类的对象,编译器会优先调用移动构造函数来完成此操作。只有当类中没有合适的移动构造函数时,编译器才会退而求其次,调用拷贝构造函数。

这意味着,移动构造函数的参数是一个右值或者将亡值的引用;

也就是说,使用一个右值,或者将亡值初始化另一个对象的时候,才会调用移动构造函数

举例两个场景

(eg1:某个成员函数,返回该类型自己的对象的场景) string 的string operator+();:

img

可以看到,有了移动构造以后,我们避免了拷贝临时变量,再释放临时变量的操作,我们直接把临时变量内的指针转移给了要赋值的对象,避免了多余的拷贝,提高了效率!

(eg2:move() 函数强制让一个左值变成右值,因此a=move(b),等号右边是右值,那么调用的就是移动构造函数:

执行过程:

  1. move让b变成了右值,走了移动构造;,把b中的各种资源转移给了a;
  2. b完成转移以后,其中的资源置空nullptr,代表他的生命周期结束了,置空的原因是防止对同一个地址2次析构等;

很明显,移动构造的优势:

  1. 减少了额外深拷贝的时间上的开销;
  2. 不需要给构造的对象分配内存,因为我们把参数(右值)的资源转移过去就行;

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

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

相关文章

2022年终结——人生中最美好的一站

文章目录前言回顾2022工作上学习上投资上生活上展望2023工作学习投资生活总结有一种责任与压力&#xff0c;叫做上有老下有小&#xff0c;但有一种幸福也叫做上有老下有小&#xff0c;当你遭遇挫折与困难时&#xff0c;这些“老小”以及那个同龄的“她”是你坚实的后盾&#xf…

Redisson中的“琐事”

文章目录前言锁分类Redisson可重入锁&#xff08;Reentrant Lock&#xff09;公平锁&#xff08;Fair Lock&#xff09;联锁&#xff08;MultiLock&#xff09;红锁&#xff08;RedLock&#xff09;读写锁&#xff08;ReadWriteLock&#xff09;信号量&#xff08;Semaphore&am…

【C++】左值、右值、语义移动和完美转发

右值引入的目的是为了对象移动&#xff1a; 因为在很多情况下&#xff0c;对象拷贝会经常发生&#xff0c;但是很多对象在拷贝后就直接被销毁了。这对性能是一个很大损耗。在重新分配内存的时候&#xff0c;从旧的内存将元素拷贝到新的内存中是不必要的。更好的方法是移动元素。…

论文投稿指南——中文核心期刊推荐(天文、测绘学)

【前言】 &#x1f680; 想发论文怎么办&#xff1f;手把手教你论文如何投稿&#xff01;那么&#xff0c;首先要搞懂投稿目标——论文期刊 &#x1f384; 在期刊论文的分布中&#xff0c;存在一种普遍现象&#xff1a;即对于某一特定的学科或专业来说&#xff0c;少数期刊所含…

使用Kalibr问题汇总:ModuleNotFoundError: No module named ‘wx‘

问题1&#xff1a; 报错&#xff1a;/kalibr_ws/src/Kalibr/Schweizer-Messer/sm_python/python/sm/PlotCollection.py", line 4, in import wx ModuleNotFoundError: No module named ‘wx’ 解决&#xff1a; sudo apt-get install python3-wxgtk4.0问题2&#xff1…

MySQL补齐函数LPAD和RPAD之SQLite解决方案

工作中经常需要对数据进行清洗&#xff0c;并对个别字段进行格式化处理&#xff0c;像 字符串左右补齐。MySQL数据库自带有LPAD()、RPAD()&#xff0c;而SQLite数据库没有的相应函数&#xff0c;需要自己转换。 目录 1、MySQL数据库 1.1、MySQL左右补全函数 1.2、实践验证 …

阶段性回顾(5)与一些题目实例(数组合并,有序判断,删除元素,进制问题等)

tips 1. 内存栈区的使用习惯是先使用高地址&#xff0c;再使用低地址。并且你还要清楚&#xff1a;随着数组下标的增大&#xff0c;其元素的地址也是在不断变高&#xff1b;对于一个占多个内存单元的变量进行取地址&#xff0c;取出来的是其所占内存空间最低地址的内存单元的地…

Python内存机制 -- = 赋值操作

Python内存机制 python的万物皆对象可不只是说说而已。 1. 预备知识&#xff1a; id()&#xff1a;可以将id()理解为C语言中的*&#xff0c;其返回当前对象在内存中的地址。 int p id(object) # id函数返回对象object在其生命周期内位于内存中的地址&#xff0c;id函数的参数…

Python数据分析案例18——化学分子数据模型(机器学习分类问题全流程)

1. 引言 1.1设计背景 对分子进行分类&#xff0c;对于筛选特定疾病的候选药物是至关重要的。传统的机器学习算法可以对分子进行分类&#xff0c;但是分子不能直接作为机器学习模型的输入&#xff0c;需要进行大量的实验从分子中得到一系列的分子特性。将分子特征使用数字化进…

47-Jenkins-终止构建并设置构建结果

终止构建并设置构建结果前言获取构建结果终止构建并设置构建状态权限问题解决前言 本篇来学习Jenkins终止构建的方法&#xff0c;使用场景&#xff1a;根据前一个构建状态&#xff0c;判断当前构建是否运行 获取构建结果 上次构建结果&#xff1a;currentBuild.getPreviousB…

【LeetCode题目详解】(五)144.二叉树的前序遍历、94.二叉树的中序遍历、145.二叉树的后序遍历、104.二叉树的最大深度、110.平衡二叉树

目录 一、力扣第144题&#xff1a;二叉树的前序遍历 1.解题思路 2.解题代码 二、力扣第94题&#xff1a;二叉树的中序遍历 三、力扣第145题&#xff1a;二叉树的后序遍历 四、力扣第104题&#xff1a;二叉树的最大深度 1.解题思路 2.解题代码 五、力扣第110题&#xff1…

抖音直播间弹幕rpc学习

目标url 随便找个直播间即可。 https://live.douyin.com/198986091107 接口分析 首先并没有在xhr下找到对应的接口 因为采用了websocket来传输信息。切换到ws即可看到 消息下&#xff0c;可以看到16进制的数据在源源不断地增加。 那么我们只要找到反序列化后的数据&…

在wsl下开发T113的主线linux(4)-编译kernel

接下来编译kernel&#xff0c;编译过程可能会出现缺少命令的报错&#xff0c;大概是下面这几个 sudo apt update sudo apt install flex bison bc libncurses-dev 目前linux主线的最新版本并没有适配t113的相关外设驱动&#xff0c;虽然能启动并串口打印&#xff0c;但其他的…

在单选按钮上实现双击效果

如果想让你的用户体验更加极致&#xff0c;可以考虑在对话框上的单选按钮上实现双击效果&#xff0c;以此作为”选中 确定”&#xff08;或者是选中 下一页&#xff0c;或者是选中 完成等&#xff09;的快捷方式。 看看我们需要怎么做 下面是一个对话框模板以及它对应的对…

3.服务注册和远程调用-Nacos[作为注册中心]

1.SpringCloud Alibaba-Nacos[作为注册中心] Nacos 是阿里巴巴开源的一个更易于构建云原生应用的动态服务发现、配置管理和服务管理 平台。他是使用 java 编写。需要依赖 java 环境 Nacos 文档地址: https://nacos.io/zh-cn/docs/quick-start.html 下载 nacos-server https://…

HCIA作业整理(2022.12.29)

一、特殊的ip地址&#xff1a; 1.环回地址&#xff1a;127.0.0.1-127.255.255.254 2.受限广播地址&#xff1a;255.255.255.255 3.直接广播地址&#xff1a;主机位全为1、192.168.1.X/24 --- 192.168.1.255 4.网段&#xff1a;主机位全0 --- 192.168.1.X/24 --- 192.168.1…

STL剖析(一):体系结构概览

一.什么是STL? STL全称是Standard Template Library&#xff0c;它属于泛型编程的范畴&#xff08;泛型编程的代表性作品&#xff09;&#xff0c;泛型编程旨在编写独立于数据类型的代码&#xff0c;也就是说代码中的数据类型只有在编译的时候才会确定&#xff0c;否则为一个…

网络协议(一):基本概念、计算机之间的连接方式

网络协议系列文章 网络协议(一)&#xff1a;基本概念、计算机之间的连接方式 目录一、网络互联模型二、计算机之间的通信基础1、计算机之间的连接方式 - 网线直连2、计算机之间的连接方式 - 同轴电缆(Coaxial)3、计算机之间的连接方式 - 集线器(Hub)4、计算机之间的连接方式 -…

vue3 antd项目实战——Form表单的重置与重置【resetFields重置表单未生效(手写重置函数)】

vue3 antd项目实战——resetFields重置表单无效【手写重置函数重置表单数据】关于form表单的文章合集场景复现原因分析解决方案(手写清空函数)关于form表单的文章合集 文章内容文章链接Form表单提交和校验https://blog.csdn.net/XSL_HR/article/details/128495087?spm1001.20…

Hadoop高手之路5-MapRreduce

文章目录Hadoop高手之路5-MapReduce分布式计算框架一、MapReduce概述1.MapReduce核心思想2.MapReduce编程模型3.MapReduce编程实例——词频统计二、MapReduce的工作原理1. MapReduc的工作过程1) 分片、格式化数据源2) 执行MapTask3) 执行Shuffle4) 执行ReduceTask5) 写入文件2.…