拷贝构造函数的参数类型必须是引用

CRISPR筛选全流程指南:从文库构建到数据分析实战 功能基因组学研究需要高效解析基因型与表型的关联,高通量筛选技术是其中的关键工具。基于CRISPR系统的筛选方法通过大规模sgRNA文库扰动基因功能,结合慢病毒递送和测序分析,能够系统鉴定影响细胞增殖、耐药、病毒感染的候选基因。与RNAi或化学小分子筛选相比,CRISPR筛选具有覆盖全基因组、脱靶率低、信号清晰等优势,已广泛应用于药物靶点发现、合成致死和免疫治疗机制研究。本文围绕实验设计与操作中的核心要点展开,涵盖文库扩增、病毒滴度控制、MOI把握、筛选模式选择以及基于MAGeCK的sgRNA丰度分析,并针对 阅读详情

在C++中, 构造函数,拷贝构造函数,析构函数和赋值函数(赋值运算符重载)是最基本不过的需要掌握的知识。 但是如果我问你“拷贝构造函数的参数为什么必须使用引用类型?”这个问题, 你会怎么回答? 或许你会回答为了减少一次内存拷贝? 很惭愧的是,我的第一感觉也是这么回答。不过还好,我思索一下以后,发现这个答案是不对的。

原因:
       如果拷贝构造函数中的参数不是一个引用,即形如CClass(const CClass c_class),那么就相当于采用了传值的方式(pass-by-value),而传值的方式会调用该类的拷贝构造函数,从而造成无穷递归地调用拷贝构造函数。因此拷贝构造函数的参数必须是一个引用。
       需要澄清的是,传指针其实也是传值,如果上面的拷贝构造函数写成CClass(const CClass* c_class),也是不行的。事实上,只有传引用不是传值外,其他所有的传递方式都是传值。

       先从一个小例子开始:(自己测试一下自己看看这个程序的输出是什么?)

[cpp]  view plain copy
  1. #include<iostream>  
  2. using namespace std;  
  3.   
  4. class CExample  
  5. {  
  6. private:  
  7.     int m_nTest;  
  8.   
  9. public:  
  10.     CExample(int x) : m_nTest(x)      //带参数构造函数  
  11.     {   
  12.         cout << "constructor with argument"<<endl;  
  13.     }  
  14.   
  15.     // 拷贝构造函数,参数中的const不是严格必须的,但引用符号是必须的  
  16.     CExample(const CExample & ex)     //拷贝构造函数  
  17.     {  
  18.         m_nTest = ex.m_nTest;  
  19.         cout << "copy constructor"<<endl;  
  20.     }  
  21.   
  22.     CExample& operator = (const CExample &ex)   //赋值函数(赋值运算符重载)  
  23.     {     
  24.         cout << "assignment operator"<<endl;  
  25.         m_nTest = ex.m_nTest;  
  26.         return *this;  
  27.     }  
  28.   
  29.     void myTestFunc(CExample ex)  
  30.     {  
  31.     }  
  32. };  
  33.   
  34. int main(void)  
  35. {  
  36.     CExample aaa(2);  
  37.     CExample bbb(3);  
  38.     bbb = aaa;  
  39.     CExample ccc = aaa;  
  40.     bbb.myTestFunc(aaa);  
  41.   
  42.     return 0;     
  43. }  
这个例子的输出结果是:

[cpp]  view plain copy
  1. constructor with argument        // CExample aaa(2);  
  2. constructor with argument        // CExample bbb(3);  
  3. assignment operator              // bbb = aaa;  
  4. copy constructor                 // CExample ccc = aaa;  
  5. copy constructor                 //  bbb.myTestFunc(aaa);  

如果你能一眼看出就是这个结果的话, 恭喜你,可以站起来扭扭屁股,不用再往下看了。

如果你的结果和输出结果有误差, 那拜托你谦虚的看完。

第一个输出: constructor with argument      // CExample aaa(2);

如果你不理解的话, 找个人把你拖出去痛打一顿,然后嘴里还喊着“我是二师兄,我是二师兄.......”

第二个输出:constructor with argument     // CExample bbb(3);

分析同第一个

第三个输出: assignment operator                // bbb = aaa;

第四个输出: copy constructor                      // CExample ccc = aaa;

这两个得放到一块说。 肯定会有人问为什么两个不一致。原因是, bbb对象已经实例化了,不需要构造,此时只是将aaa赋值给bbb,只会调用赋值函数,就这么简单,还不懂的话,撞墙去! 但是ccc还没有实例化,因此调用的是拷贝构造函数,构造出ccc,而不是赋值函数,还不懂的话,我撞墙去!!

 

第五个输出: copy constructor                      //  bbb.myTestFunc(aaa);

实际上是aaa作为参数传递给bbb.myTestFunc(CExample ex), 即CExample ex = aaa;和第四个一致的, 所以还是拷贝构造函数,而不是赋值函数, 如果仍然不懂, 我的头刚才已经流血了,不要再让我撞了,你就自己使劲的再装一次吧。

通过这个例子, 我们来分析一下为什么拷贝构造函数的参数只能使用引用类型。

看第四个输出: copy constructor                      // CExample ccc = aaa;

构造ccc,实质上是ccc.CExample(aaa); 我们假如拷贝构造函数参数不是引用类型的话, 那么将使得 ccc.CExample(aaa)变成aaa传值给ccc.CExample(CExample ex),即CExample ex = aaa,因为 ex 没有被初始化, 所以 CExample ex = aaa 继续调用拷贝构造函数,接下来的是构造ex,也就是 ex.CExample(aaa),必然又会有aaa传给CExample(CExample ex), 即 CExample ex = aaa;那么又会触发拷贝构造函数,就这下永远的递归下去。

所以绕了那么大的弯子,就是想说明拷贝构造函数的参数使用引用类型不是为了减少一次内存拷贝, 而是避免拷贝构造函数无限制的递归下去。

附带说明,在下面几种情况下会调用拷贝构造函数:
a、   显式或隐式地用同类型的一个对象来初始化另外一个对象。如上例中,用对象c初始化d;
b、  作为实参(argument)传递给一个函数。如CClass(const CClass c_class)中,就会调用CClass的拷贝构造函数;
c、  在函数体内返回一个对象时,也会调用返回值类型的拷贝构造函数;
d、  初始化序列容器中的元素时。比如 vector<string> svec(5),string的缺省构造函数和拷贝构造函数都会被调用;
e、  用列表的方式初始化数组元素时。string a[] = {string(“hello”), string(“world”)}; 会调用string的拷贝构造函数。
如果在没有显式声明构造函数的情况下,编译器都会为一个类合成一个缺省的构造函数。如果在一个类中声明了一个构造函数,那么就会阻止编译器为该类合成缺省的构造函数。和构造函数不同的是,即便定义了其他构造函数(但没有定义拷贝构造函数),编译器总是会为我们合成一个拷贝构造函数。
另外函数的返回值是不是引用也有很大的区别,返回的不是引用的时候,只是一个简单的对象,此时需要调用拷贝构造函数,否则,如果是引用的话就不需要调用拷贝构造函数。
[cpp]  view plain copy
  1. #include<iostream>  
  2. using namespace std;  
  3.   
  4. class A  
  5. {  
  6. private:  
  7.     int m_nTest;  
  8. public:  
  9.     A()  
  10.     {  
  11.     }  
  12.     A(const A& other)    //构造函数重载  
  13.     {  
  14.         m_nTest = other.m_nTest;  
  15.         cout << "copy constructor"<<endl;    
  16.     }  
  17.     A & operator =(const A& other)  
  18.     {  
  19.         if(this != &other)  
  20.         {  
  21.             m_nTest = other.m_nTest;  
  22.             cout<<"Copy Assign"<<endl;  
  23.         }  
  24.         return *this;  
  25.     }  
  26. };  
  27.   
  28. A fun(A &x)  
  29. {  
  30.     return x;     //返回的不是引用的时候,需要调用拷贝构造函数  
  31. }  
  32.   
  33. int main(void)  
  34. {  
  35.     A test;  
  36.     fun(test);  
  37.     system("pause");  
  38.     return 0;  
  39. }  

分享一道笔试题目,编译运行下图中的C++代码,结果是什么?(A)编译错误;(B)编译成功,运行时程序崩溃;(C)编译运行正常,输出10。请选择正确答案并分析原因。

[cpp]  view plain copy
  1. class A  
  2. {  
  3. private:  
  4.     int value;  
  5. public:  
  6.     A(int n)  
  7.     {  
  8.         value = n;  
  9.     }  
  10.   
  11.     A(A other)  
  12.     {  
  13.         value = other.value;  
  14.     }  
  15.     void Print()  
  16.     {  
  17.         cout<<value<<endl;  
  18.     }  
  19. };  
  20.   
  21. int main(void)  
  22. {  
  23.     A a = 10;  
  24.     A b = a;  
  25.     b.Print();  
  26.     return 0;  
  27. }  
答案:编译错误。在复制构造函数中传入的参数是A的一个实例。由于是传值,把形参拷贝到实参会调用复制构造函数。因此如果允许复制构造函数传值,那么会形成永无休止的递归并造成栈溢出。因此C++的标准不允许复制构造函数传值参数,而必须是传引用或者常量引用。在Visual Studio和GCC中,都将编译出错。
python 爬虫 xpath 存储到数据库 参考 阅读详情

相关推荐

内存优化--LOGBACK导致内存告警

一.故事背景 由于开辟新市场需要,开发了新的项部署在海外平台,其中最消耗内存的功能是消费kafka消息(最开始预计一天有1千万的量),部署完之后运行一段时间发现出现内存告警问题。 二.分析问题 出现内存告警,(新项目是低配置机器 2C4G * 2台)第一个念头是去查看堆空间设置的情况,看到jvm启动命令中堆空间都是直接指定大小,说明问题不是出在堆空间 -Xmx3g -Xms3g 先不管这些,去查看总的内存使用情况,发现总的内存空间使用将近有92% = 3.68G,那么这多出来使用的0.6

qq_33199919的博客 6051

拷贝构造函数的参数类型为什么必须是引用

如果参数类型是非常量引用,那么拷贝构造函数只能接受非常量对象作为参数,无法接受常量对象。当拷贝构造函数的参数不是引用类型时,而是传值(by value),会触发另一个拷贝构造函数的调用。拷贝构造函数的参数类型必须是引用,通常是常量引用(const reference),是因为拷贝构造函数在创建对象的副本时需要获取源对象的值。通过引用,拷贝构造函数只会获取源对象的引用,并不会触发额外的拷贝构造函数调用。总结起来,拷贝构造函数的参数类型必须是引用(通常是常量引用),以避免递归调用和提供更大的灵活性。

xiao23597的博客 2304

老服务器焕新记:在Dell R730上折腾Nvidia K80显卡的完整记录(含Anaconda环境配置)

本文详细记录了在Dell R730服务器上为Nvidia K80计算卡安装驱动、配置CUDA及Anaconda环境的完整过程。文章重点解决了老旧硬件与CentOS 7系统的兼容性问题,提供了从BIOS设置、驱动版本精准匹配到Python机器学习环境搭建的实战指南,旨在帮助读者低成本挖掘旧服务器的GPU计算潜力。

weixin_29197835的博客 502

拷贝构造函数为什么要传入引用

在拷贝构造函数中,如果我们将参数作为值传递,那么会发生对象复制,这将导致无限递归的调用,因为拷贝构造函数的调用需要创建一个新对象并将其初始化为另一个对象的副本。用MyClass 类实例对象obj2,后面的(obj1)是告诉编译器调用拷贝构造函数,值传递会不断调用构造函数,我们不能控制,因为值传递时会把obj1赋值給临时变量,并调用拷贝构造函数,不断往复。将d1的值传递给dd1,因为是值传递,一旦调用又要产生临时变量ddd1,将d1的值传递给临时变量ddd1,那么问题就很明显了,(我们的本意,最终目的。

qq_53206057的博客 1699

逆向实战:我是如何一步步解开美团外卖App的mtgsig3.0签名(附关键代码片段)

本文详细记录了逆向分析美团外卖App的mtgsig3.0签名算法的全过程,从抓包到算法还原,包括Java层和Native层的深度分析。通过Frida、IDA Pro等工具,揭示了签名生成的多层加密流程,并提供了关键代码片段。文章还探讨了逆向工程中的反调试对抗和签名时效性问题,为安全研究人员提供了宝贵的技术参考。

weixin_42530732的博客 871

从零组装一台会‘看’的无人机:手把手教你配置NUC机载电脑与D435深度相机(环境搭建篇)

本文详细介绍了如何从零开始组装一台具备视觉能力的智能无人机,重点讲解了NUC机载电脑与D435深度相机的配置方法。通过Ubuntu系统安装、ROS环境搭建、深度学习框架配置等步骤,帮助开发者实现无人机的自主避障和目标跟踪功能。文章还提供了性能优化和常见问题解决方案,是无人机视觉系统开发的实用指南。

weixin_30915275的博客 396

拷贝构造函数的类型为什么必须使用引用类型

在C++中, 构造函数,拷贝构造函数,析构函数和赋值函数(赋值运算符重载)是最基本不过的需要掌握的知识。 但是如果我问你“拷贝构造函数的参数为什么必须使用引用类型?”这个问题, 你会怎么回答? 原因: 如果拷贝构造函数中的参数不是一个引用,即形如CClass(const CClass c_class),那么就相当于采用了传值的方式(pass-by-value),而传值的方式会调用该类的拷贝构造函数,从而造成无穷递归地调用拷贝构造函数。因此拷贝构造函数的参数必须是一个引用。 菜鸟的话记住...

追求卓越583的博客 5659

你一直忽略的神器:离你最近的超强语音输入法(微信语音输入全攻略,支持全局混用)

你一直忽略的语音输入工具🎤 ,其实就在身边!无需额外软件,即可实现全局语音转文字⚡ 支持中英文混输,还能与其他输入法混合使用,聊天、办公都能高效完成,让你的输入效率轻松翻倍🚀

XiaoqiangClub的博客 904

拷贝构造函数的参数为什么必须使用引用类型

在C++中, 构造函数,拷贝构造函数,析构函数和赋值函数(赋值运算符重载)是最基本不过的需要掌握的知识。 但是如果我问你“拷贝构造函数的参数为什么必须使用引用类型?”这个问题, 你会怎么回答? 或许你会回答为了减少一次内存拷贝? 很惭愧的是,我的第一感觉也是这么回答。不好还好,我有理性这个好品质。思索一下以后,发现这个答案是不对的。让我来撕开(有点暴力,但是我喜欢,嘿嘿--龇牙)那件隐藏

『小猪呼噜噜』的专栏 -- I Write,therefore I am. 9136

NL2SQL实践系列(1):深入解析Prompt工程在text2sql中的应用技巧

NL2SQL实践系列(1):深入解析Prompt工程在text2sql中的应用技巧

丨汀、的博客 4327

PCL Alpha Shapes平面点云边界特征提取【2026最新版】

alpha shapes算法用于平面点云的边界特征提取。博客长期更新,本文最近一次更新时间为:2026年4月20日。

点云侠的博客 27万+

c++中拷贝构造函数的参数类型必须是引用

转自:http://3lian.com/edu/2013/07-18/82007.html如果拷贝构造函数中的参数不是一个引用,即形如CClass(const CClass c_class),那么就相当于采用了传值的方式(pass-by-value),而传值的方式会调用该类的拷贝构造函数,从而造成无穷递归地调用拷贝构 造函数。因此拷贝构造函数的参数必须是一个引用在C++中, 构造函数,拷贝构造函数,

yongheng_1999的博客 1940

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

【C++】C++中拷贝构造函数的参数类型必须是引用

在C++中, 构造函数,拷贝构造函数,析构函数和赋值函数(赋值运算符重载)是最基本不过的需要掌握的知识。 但是如果我问你“拷贝构造函数的参数为什么必须使用引用类型?”这个问题, 你会怎么回答? 或许你会回答为了减少一次内存拷贝? 很惭愧的是,我的第一感觉也是这么回答。不过还好,我思索一下以后,发现这个答案是不对的。 原因: 如果拷贝构造函数中的参数不是一个引用,即形如CClass(const CClass c_class),那么就相当于采用了传值的方式(pass-by-value),而传值的方式会调用该类

Begin 1340

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

C++中类的拷贝构造函数的参数类型必须是引用解惑。

     在C++中, 构造函数,拷贝构造函数,析构函数和赋值函数(赋值运算符重载)是最基本不过的需要掌握的知识。 但是如果我问你“拷贝构造函数的参数为什么必须使用引用类型?”这个问题, 你会怎么回答? 或许你会回答为了减少一次内存拷贝? 很惭愧的是,我的第一感觉也是这么回答。不过还好,我思索一下以后,发现这个答案是不对的。 原因:        如果拷贝构造函数中的参数不是一个引用,即形如CCl...

渐行渐远 2394

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

拷贝构造函数的参数类型(必须引用类型)

       在C++中, 构造函数,拷贝构造函数,析构函数和赋值函数(赋值运算符重载)是最基本不过的需要掌握的知识。 但是如果我问你“拷贝构造函数的参数为什么必须使用引用类型?”这个问题, 你会怎么回答? 或许你会回答为了减少一次内存拷贝? 很惭愧的是,我的第一感觉也是这么回答。不过还好,我思索一下以后,发现这个答案是不对的。 原因:...

Yezy 741

为什么拷贝构造函数自己的参数必须是“引用类型”

书上解释说: 如果其参数不是引用类型,则调用永远也不会成功—— 为了调用拷贝构造函数,我们必须拷贝它的实参,但为了拷贝实参,我们又需要调用拷贝构造函数,如此无限循环。 我就一个状态:??? 这是在说啥???把我自己搞糊涂了,这到底是什么意思??? 分句来理解。 第一句:为了调用拷贝构造函数,我们必须拷贝它的实参。 这句话还是很容易理解的,因为不是引用类型,那么拷贝构造函数中的形参,需要使用一个实参的拷贝,也就是需要拷贝一个实参。 第二句:但为了拷贝实参,我们又需要调用拷贝构造函数 但是拷贝构造函数需要是本类

“时光清浅,不觉多年”的博客 614
上一篇: TCP中的流量控制及拥塞控制
下一篇: 哈佛人告诉你怎样学习 怎样培养人高贵的气质
otuhacker
博客等级 码龄18年 21粉丝 84原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值