C++拷贝构造函数

c++填空题 5-1 阅读下面的程序,完成其中复制构造函数的代码。 #include <iostream> using namespace std; class CAT { public: CAT(); CAT(const CAT&); ~CAT(); int GetAge() const { return *itsAge; } void SetAge(int age){ *itsAg 阅读详情

摘要:

1.代码格式牢记。类名(const 类名 &X)

2.该函数的三种调用时机。

3.浅拷贝与深拷贝(是否有动态成员变量)。

一、什么是拷贝构造函数

例1:

#include <iostream>  
using namespace std;  

class CExample {  
private:  
	int a;  
public:  
	//构造函数  
	CExample(int b)  
	{ a = b;}  

	//拷贝构造函数  
	CExample(const CExample& C)  
	{  
		a = C.a;  
	}  

	//一般函数  
	void Show ()  
	{  
		cout<<a<<endl;  
	}  
};  

int main()  
{  
	CExample A(100);  
	CExample B = A; // CExample B(A); 也是一样的  
	B.Show ();  
	return 0;  
}   
系统为对象B分配了内存并完成了与对象A的复制过程。就类对象而言, 相同类型的类对象是通过拷贝构造函数来完成整个复制过程的。CExample(const CExample& C)就是我们自定义的拷贝构造函数。可见,拷贝构造函数是一种特殊的构造函数,它 必须的一个参数是本类型的一个引用变量。

二、拷贝构造函数的调用时机

在C++中,下面三种对象需要调用拷贝构造函数!

1.对象以值传递的方式传入函数参数

例2:

#include <iostream>
using namespace std;

class CExample   
{  
private:  
	int a;  

public:  
	//构造函数  
	CExample(int b)  
	{   
		a = b;  
		cout<<"creat: "<<a<<endl;  
	}  

	//拷贝构造  
	CExample(const CExample& C)  
	{  
		a = C.a;  
		cout<<"copy"<<endl;  
	}  

	//析构函数  
	~CExample()  
	{  
		cout<< "delete: "<<a<<endl;  
	}  

	void Show ()  
	{  
		cout<<a<<endl;  
	}  
};  

//全局函数,传入的是对象  
void g_Fun(CExample C)  
{  
	cout<<"test"<<endl;  
}  

int main()  
{  
	CExample test(1);  
	//传入对象  
	g_Fun(test);  
	return 0;  
}  
g_Fun(test) 执行步骤:

①test对象传入形参时,会产生一个临时变量,设为C。

②然后调用拷贝构造函数把test的值给C。

③等g_Fun()执行完成后,析构C对象。

2.对象以值传递的方式从函数返回

例3:

#include <iostream>
using namespace std;

class CExample   
{  
private:  
	int a;  

public:  
	//构造函数  
	CExample(int b)  
	{   
		a = b;  
	}  

	//拷贝构造  
	CExample(const CExample& C)  
	{  
		a = C.a;  
		cout<<"copy"<<endl;  
	}  

	void Show ()  
	{  
		cout<<a<<endl;  
	}  
};  

//全局函数  
CExample g_Fun()  
{  
	CExample temp(0);  
	return temp;  
}  

int main()  
{  
	g_Fun();  
	return 0;  
}  
当g_Fun()函数执行到return时,会产生以下几个重要步骤:

①先会产生一个临时变量,就叫XXXX吧。

②然后调用拷贝构造函数把temp的值给XXXX。整个这两个步骤有点像:CExample XXXX(temp);

③在函数执行到最后先析构temp局部变量。(析构顺序)

④等g_Fun()执行完后再析构掉XXXX对象。

3.对象需要另外一个对象初始化

CExample A(100);  
CExample B = A; 
最后一句会调用拷贝构造函数。
若程序如下,则不会调用拷贝构造函数。即:CExample B = A;与B = A;的区别。

CExample a(1);
CExample b(2);
b = a;
最后一句为调用拷贝构造函数,调用了等号运算符重载。程序代码示例如下(注意其中this与*this区别)

CExample &operator=( const CExample &rhs )
{
	if ( this == &rhs ) {
            return *this;
        }
        this->a = rhs.a;
        return *this;
}

三、浅拷贝与深拷贝

系统自带默认的拷贝构造函数。

1.浅拷贝

只对对象中的数据成员进行简单的赋值。大多数情况下“浅拷贝”已经能很好地工作了,但是一旦对象存在了动态成员,那么拷贝就会出问题了。如下代码:

    class Rect  
    {  
    public:  
        Rect()      // 构造函数,p指向堆中分配的一空间  
        {  
            p = new int(100);  
        }  
        ~Rect()     // 析构函数,释放动态分配的空间  
        {  
            if(p != NULL)  
            {  
                delete p;  
            }  
        }  
    private:  
        int width;  
        int height;  
        int *p;     // 一指针成员  
    };  
      
    int main()  
    {  
        Rect rect1;  
        Rect rect2(rect1);   // 复制对象  
        return 0;  
    }  
error:进行对象复制时,对于动态分配的内容没有进行正确的操作。

在运行定义rect1对象后,由于在构造函数中有一个动态分配的语句,因此执行后的内存情况大致如下:

在使用rect1复制rect2时,由于执行的是拷贝,只是将成员的值进行赋值,这时rect1.p=rect2.p,也即这两个指针指向了堆里的同一个空间,如下如所示:

当然,这不是我们所期望的结果,在销毁对象时,两个对象的析构函数将对同一个内存空间释放两次,这就是错误出现的原因。我们需要的不是两个p有相同的值,而是两个p指向的空间有相同的值。解决办法就是使用“深拷贝”。

2.深拷贝

在“深拷贝”的情况下,对于对象中动态成员,应该重新动态分配空间,如下所示。

    class Rect  
    {  
    public:  
        Rect()      // 构造函数,p指向堆中分配的一空间  
        {  
            p = new int(100);  
        }  
        Rect(const Rect& r)  
        {  
            width = r.width;  
            height = r.height;  
            p = new int;    // 为新对象重新动态分配空间  
            *p = *(r.p);  
        }  
        ~Rect()     // 析构函数,释放动态分配的空间  
        {  
            if(p != NULL)  
            {  
                delete p;  
            }  
        }  
    private:  
        int width;  
        int height;  
        int *p;     // 一指针成员  
    };  
完成对象复制后,内存情况如下所示:

此时rect1的p和rect2的p各自指向一段内存空间,但它们指向的空间具有相同的内容,这就是所谓的“深拷贝”。


参考:

http://blog.youkuaiyun.com/lwbeyond/article/details/6202256

SAP 资产主数据屏幕增强:对比字段追加与子屏幕/页签 2 种方案优劣 本文深入对比了SAP资产主数据(AS01/AS03)屏幕增强的两种方案:字段追加与子屏幕/页签。从技术实现、业务适配、系统维护等维度分析各自优劣,提供方案选型决策树和混合方案实践建议,帮助企业在SAP实施中做出最优选择。 阅读详情

相关推荐

STM32硬件SPI驱动W5500以太网模块全流程(附避坑指南)

本文详细介绍了STM32硬件SPI驱动W5500以太网模块的全流程,包括硬件架构设计、SPI接口选型、官方驱动移植、网络协议栈配置与优化等关键步骤。通过实战案例和性能对比数据,帮助开发者快速实现稳定高效的网络连接,特别提供了常见问题排查指南和性能调优技巧。

weixin_29194693的博客 268

C++--复制构造函数

测试代码 #include<iostream> using namespace std; class point{ public: point(double a,double b); ~point(); point(point &p); void fun1(point p); point fun2(); double getx() { return x...

海到无边天作岸 山登绝顶我为峰 1782

STM32 A/B分区OTA升级实战:从原理到避坑指南

本文详细解析STM32 A/B分区OTA升级的核心原理与实战实现,涵盖双分区设计、Bootloader开发、固件传输验证及常见问题解决方案。重点介绍通过A/B分区实现无缝升级与安全回滚的机制,帮助开发者规避典型陷阱,提升嵌入式系统远程更新的可靠性与效率。

qqq44的博客 1109

第六周阅读程序5:复制构造函数运行机制

#include using namespace std; class AA { public: AA(int i,int j) { A=i; B=j; cout<<"Constructor\n"; } AA(AA &obj) { A=obj.A+1;

Destiny_Forever的专栏 603

Ubuntu终端接入Codex:一行脚本搞定AI编程助手安装与配置

在开发者日常工作中,命令行终端是最高频的操作环境,而AI编程助手的出现正在改变传统的编码方式。通过将大模型能力与终端工具链结合,开发者无需切换窗口即可完成命令查询、代码生成、项目理解和自动执行等任务。Ubuntu作为服务器和开发机的主流系统,搭配Node.js生态和API Key认证,即可在本地闭环运行AI助手。本文从环境准备、密钥配置、权限管理到自动化脚本封装,系统拆解在终端中接入Codex的完整流程,并分享高频用法与实测排障经验,帮助开发者安全、高效地让AI融入命令行工作流。

weixin_29061041的博客 322

Win11 C盘爆满别慌!手把手教你安全迁移AppData和用户文件夹(附一键脚本)

本文针对Win11 C盘空间不足问题,提供了一套安全有效的解决方案。通过深入解析用户目录结构,指导用户利用符号链接和Robocopy工具,将AppData、下载文档等占用大户迁移至其他分区,并附带了自动化脚本,从根本上实现C盘瘦身,同时确保系统稳定和数据安全。

weixin_29231221的博客 2090

pta c++ 程序填空题

pta c++ 判断题 类与对象 数据共享与保护 数组 指针 字符串 继承与派生 多态性 群体类和群体数据的组织 泛型程序设计 流类库与输入输出 异常处理 stl 面向对象程序设计 成员函数 构造函数 析构函数 类的组合 作用域 静态 动态 友元 常对象 多文件结构 对象数组 this指针 动态内存分配 引用 虚函数 抽象类 运算符重载 函数模板 类模板 容器

weixin_62566689的博客 5054

基于 YOLO + SAM 的自动图像标注实战

摘要: 本文提出一种基于YOLO检测和SAM分割的自动化数据标注流水线方案,通过YOLO定位目标并生成检测框,再以检测框为提示驱动SAM完成精细分割,最终输出YOLO格式的标注文件。该方案将人工标注升级为半自动流程,显著提升标注效率,尤其适用于多类别、大规模图像的实例级标注需求。代码模块化设计支持模型灵活替换,并集成异常处理与进度可视化功能。虽依赖YOLO检测质量且对小目标存在局限,但作为工程落地方案,可有效降低私有数据集构建成本,适用于工业检测、遥感等场景的冷启动标注。

qq_64366203的博客 1148

CPP-基础:C++拷贝构造函数详解

一. 什么是拷贝构造函数 首先对于普通类型的对象来说,它们之间的复制是很简单的,例如: 1 int a = 100; 2 int b = a; 而类对象与普通对象不同,类对象内部结构一般较为复杂,存在各种成员变量。下面看一个类对象拷贝的简单例子。 1 #include <iostream> 2 using namespac...

dixiongbi7761的博客 146

别再手动找触点了!EPLAN线圈触点映像的3种显示方式与F键/Ctrl+B快捷键实战

本文详细解析EPLAN线圈触点映像的3种显示方式与F键/Ctrl+B快捷键实战技巧,帮助电气设计工程师提升图纸操作效率。通过精简编号、路径栏显示和元件旁可视化三种模式的应用场景对比,结合快捷键肌肉记忆训练法,实现触点快速定位与管理,大幅减少手动查找时间。

weixin_42522964的博客 481

YOLOv13结合Sobel边缘检测算子,实现EIEM(Edge Information Enhancement Module,边缘信息增强模块),强化空间特征提取

EIEM模块通过巧妙地结合Sobel边缘检测算子和现代卷积网络架构,实现了显式边缘信息增强的创新设计。这种方法不仅提高了网络对边缘特征的敏感性,还保持了良好的计算效率和模块化特性。 从技术实现角度看,EIEM展示了如何将经典计算机视觉算法无缝集成到深度学习框架中,为构建更强大、更可解释的视觉模型提供了新的思路。随着对边缘信息重要性认识的不断深入,以及对网络可解释性需求的增长,EIEM这样的显式特征增强模块将在未来的计算机视觉研究中发挥越来越重要的作用。

FJN110的博客 907

C++——拷贝构造函数

(用旧对象去构造新对象)拷贝构造函数,又称复制构造函数,是一种特殊的构造函数,它由编译器调用来完成一些基于同一类的其他对象的构造及初始化。值类型(不行,会产生递归);指针类型(能实现要求,但会出现歧义(感觉a的地址给b构造));引用类型(本类对象的const引用)。其唯一的形参必须是引用,但并不限制为const,一般普遍的会加上const限制。此函数经常用在函数调用时用户定义类型的值传递及返回。拷贝构造函数要调用基类的拷贝构造函数和成员函数。

weixin_59179454的博客 2万+

【Android 教程系列第 30 篇】为什么要为 App 应用加固 ?如何为 App 应用加固 ?

一:为什么要为 App 应用加固 ? 二:如何为 App 应用加固 ? 三:加固后为什么要重新签名 ?

“Allen Su”的博客 7053

cpp拷贝构造函数

1.当类含有指针时,必须自定义拷贝构造函数。 坑点: class DoubleTest { double *d; public: DoubleTest() :d(new double(123)) { cout << "constructor" << endl; } //DoubleTest(cons

wjxuanxuan的博客 928

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

C++拷贝构造函数的调用时机

C++拷贝构造函数的调用时机 一、拷贝构造函数调用的时机 ​ 当以拷贝的方式初始化对象时会调用拷贝构造函数,这里需要注意两个关键点,分别是以拷贝的方式和初始化对象 1. 初始化对象 初始化对象是指,为对象分配内存后第一次向内存中填充数据,这个过程会调用构造函数,对象被创建后必须立即初始化。也就是说只要创建对象就会调用构造函数。 2.初始化和赋值的区...

一 6044

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

cpp--拷贝构造函数详解

本文详细解释了cpp中的拷贝构造函数,包括定义和使用方法,也帮大家规避了一些易错点

2302_80295520的博客 1069

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

19 CPP拷贝构造函数

如果类中重载了拷贝构造函数却没有定义默认的拷贝构造函数,编译器会提供默认的拷贝构造函数,这一点和普通构造函数不一样。函数以值的方式返回对象时,可能会调用拷贝构造函数(VS会调用,Linux不会,g++编译器做了优化) 代码说明。但是重载的时候,形参中一定要有类本身的常引用,如果形参中没有类本身的常引用,那就成了普通构造函数。类名(.....,const 类名& 对象名,.....){......}拷贝构造函数可以重载,可以有默认参数。

wade1010的专栏 248

【C++ | 拷贝构造函数】一文了解C++的 拷贝(复制)构造函数

👉本文介绍C++的拷贝构造函数,为什么需要拷贝构造函数,什么是拷贝构造函数,怎么使用拷贝构造函数,默认拷贝构造函数。

wkd_007的博客 9727

C++ —— 拷贝构造函数

C++ —— 拷贝构造函数

MaoSiri的博客 744

C++ 拷贝构造函数

拷贝构造函数是一种特殊的构造函数,它在创建对象时,是使用同一类中之前创建的对象来初始化新创建的对象。这句话的意思是在利用拷贝构造函数创建一个新的对象时,是通过复制现有对象的数据来初始化新对象。所以说,新对象将成为现有对象的副本。

qq_51753728的博客 918

c++中拷贝构造函数被调用的时机

拷贝构造函数被调用的几种情况: (1)当用类的一个对象去初始化该类的另一个对象时,系统会自动调用拷贝构造函数; (2)将一个对象作为实参传递给一个非引用类型的形参,系统会自动调用拷贝构造函数; (3)从一个返回类为非引用的函数返回一个对象时,系统会自动调用拷贝构造函数; (4)用花括号列表初始化一个数组的元素时,系统会自动调用拷贝构造函数。 下面逐个举例: 1 当用类的一个对象去初始化该类的另一个对象时,系统会自动调用拷贝构造函数 #include<ctime> #include

StudyWinter的博客 7362

C++拷贝构造函数详解

在C++中,拷贝构造函数是一种特殊的构造函数,用于创建一个新对象,并将其初始化为现有对象的副本。拷贝构造函数的函数名必须与类名相同,并且参数为该类的一个常引用。拷贝构造函数是一种特殊的构造函数,用于创建对象的副本。他接受一个同类型的对象(本类对象的引用)作为参数,并使用该对象的数据来初始化新对象。拷贝构造函数通常用于在程序中复制对象,以便在不修改原始对象的情况下对其进行操作。拷贝构造函数通常会执行深拷贝操作,即复制指针指向的数据,而不是仅仅复制指针本身。

m0_62573214的博客 4073

C++默认拷贝构造函数

C++默认拷贝构造函数 转载来源 c++类的中有两个特殊的构造函数,(1)无参构造函数,(2)拷贝构造函数。它们的特殊之处在于: (1)当类中没有定义任何构造函数时,编译器会默认提供一个无参构造函数且其函数体为空; (2)当类中没有定义拷贝构造函数时,编译器会默认提供一个拷贝构造函数,进行成员变量之间的拷贝。(这个拷贝操作是浅拷贝) 这里只讲拷贝构造函数。在c语言中, int a = 5; //...

Meloor的博客 2890
上一篇: C++中static关键字
下一篇: 操作系统常见面试题及答案
hellorichen
博客等级 码龄13年 199粉丝 104原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值