C++拷贝构造函数(复制构造函数)

小编 2026-06-14 阅读:1628 评论:0
一、拷贝构造函数的形式 复制构造函数是构造函数的一种特殊情况。因为类的对象包含各种成员变量,在发生拷贝时不能和普通对象一样来拷贝,所以我们需要使用拷贝构造函数来进行对象拷贝。拷贝构造函数只有一个参数,参数...

一、拷贝构造函数的形式

复制构造函数是构造函数的一种特殊情况。因为类的对象包含各种成员变量,在发生拷贝时不能和普通对象一样来拷贝,所以我们需要使用拷贝构造函数来进行对象拷贝。拷贝构造函数只有一个参数,参数类型是本类的引用。

如果构造函数没有显式定义,那么编译器将会自动生成拷贝构造函数。大多数情况下,其作用是实现从源对象到目标对象逐个字节的复制,即使得目标对象的每个成员变量都变得和源对象相等。

为什么只有一个参数?

通常来说,要发生拷贝,需要两个参数。但是我们知道在类中存在一个this指针,所以其中一个参数就是this指针指向的对象,而这个对象被隐式的定义了,所以在拷贝构造函数中我们只需要给出用来初始化this指针指向对象的另一个对象。听起来是不是有点绕,简单来说,当我用一个对象去初始化另一个对象时,拷贝构造函数会发生调用,调用这个函数的对象作为this指针指向的对象,而用来初始化这个对象的对象就需要作为实参传递给拷贝构造函数,所以在拷贝构造函数中我们需要一个对象的形参来接收它。

需要注意的是,这里所说的一个参数并不真的仅仅只局限于一个参数。对象拷贝的过程是一对一的过程,所以这里的参数指的是类所定义的对象。

class Quick{
public:
	Quick(int rear=1, int imag=1)
	{
		_rear = rear;
		_imag = imag;
	}
	Quick(const Quick& ret)
	{
		_rear = ret._rear;
		_imag = ret._imag;
		cout << \"copy\" << endl;
	}
		
private:
	int _rear;
	int _imag;
};
int main()
{
	Quick s1;
	Quick s2(s1);//调用拷贝构造函数对s2进行初始化
	return 0;
}

对于一个类Quick, 如果一个构造函数的第一个参数是下列之一:

  1. Quick&
  2. const Quick&
  3. volatile Quick&
  4. const volatile Quick&

且没有其他参数或其他参数都有默认值,那么这个函数是拷贝构造函数.

例如Quick(const Quick&,int m=3)也是拷贝构造函数

为什么参数类型是本类的引用?

当调用拷贝构造函数时,假设以值的方式进行传递,将类对象的值传递过去,首先会进行临时拷贝,因为类对象的拷贝要调用临时拷贝函数,又因为使用的是值传递,所以会再次发生临时拷贝,从而进行无限递归。所以为了避免这种情况发生,请使用类的引用方式。

二、何时调用拷贝构造函数

调用拷贝构造函数一共有三种情况:

1.当用一个对象去初始化同类的另一个对象时,会引发拷贝构造函数被调用

Quick s1;
Quick s2(s1);

这里需要注意的是

Quick s1;
Quick s2;
s2=s1;

上面第三条语句是赋值语句,不是初始化语句,因为左操作数已经是一个已经定义的变量,所以并不会调用拷贝构造函数。

2.如果函数fun的参数是类Quick的对象,那么当fun被调用时,类Quick的拷贝构造函数将被调用

int main()
{
	fun(Quick ret);
	return 0;
}

3.如果函数的返冋值是类Quick的对象,则函数返冋时,类Quick的拷贝构造函数被调用

Quick Fun() {
    Quick ret(2,3);
    return ret;
}

三、浅拷贝和深拷贝

1.浅拷贝

很多前拷贝时候我们在不显式定义拷贝构造函数的情况下,编译器会给我们自动产生一个拷贝构造函数,这个编译器生成默认的拷贝构造函数对传递对象给函数参数或者函数返回对象都能很好的完成,这个默认的拷贝构造也叫做浅拷贝。这个构造函数很简单,大多数情况下,其作用是实现从源对象到目标对象逐个字节的复制,即使得目标对象的每个成员变量都变得和源对象相等。

那么为什么要自己显式定义拷贝构造函数呢?我们来看下面的代码:

class Hyottoko {
public:
	Hyottoko()
	{
		m_count++;
	}
	
	static int getCount()
	{
		return m_count;
	}
	~Hyottoko()
	{
		m_count--;
	}
private:
	int *m_next;
	int m_data;
	static int m_count;
};
int Hyottoko::m_count = 0;

int main()
{
	Hyottoko s1;//第一个对象
	Hyottoko s2(s1);//第二个对象
	cout << s2.getCount()<< endl;

	system(\"pause\");
	return 0;
}

代码要解决的问题是:获取类定义的对象的个数

在上面的代码中我们没有显式定义拷贝构造函数,使用编译器默认生成的拷贝构造函数,当我们在使用一个对象去初始化另一个对象时会对拷贝构造函数调用。对于调用默认生成的拷贝构造函数初始化的对象并没有对用于对象计数的count进行操作,所以此时虽然有两个对象,但count的值是1,同时当析构函数被调用时,count的值为-1。

这种结果时拷贝构造函数对于静态数据成员没有做出相应的处理所造成的。

如果我们在类中添加显式的拷贝构造函数就可以解决这种问题

Hyottoko(const Hyottoko& data)
	{
		m_count++;
	}

 

2.深拷贝

上面解决问题的拷贝构造函数是一种浅拷贝,那么深拷贝和浅拷贝区别在哪呢?

我们先来看看下面的代码:

class String {
public:
	String(char*str = NULL)
	{
		m_str = new char[strlen(str)+1];
		strcpy(m_str, str);
	}
	String(String& str)
	{
		strcpy(m_str, str.m_str);
	}
	~String()
	{
		if (m_str)
			delete[]m_str;
	}
private:
	char *m_str;
};
int main()
{
	String s1(\"Hello\");
	String s2(s1);

	system(\"pause\");
	return 0;
}

使用s1去初始化s2调用拷贝构造函数,我们的目的是将s1中的内容拷贝到s2的空间中,但实际上,使用浅拷贝的方式只是改变了s2的指向,让s2指向s1所指向的空间,这会使得调用析构函数时,同一空间被释放两次,造成错误;而且原来s2指向的空间没有被释放,造成内存泄露。为了解决这种问题我们需要进行深拷贝,修改类中的拷贝构造函数,修改如下:

String(String& str)
	{
		m_str = new char[strlen(str.m_str)+1];
		strcpy(m_str, str.m_str);
	}

也就是在拷贝对象前,先进行空间分配。

四、归纳总结

初始化对象的函数有两种,一个是构造函数,一个是拷贝构造函数(浅拷贝、深拷贝)。以不同的方式来初始化一个对象时,需要明确调用函数是那个,再根据需求来确定使用哪种构造函数。在重载赋值运算符时也需要注意拷贝这个问题。

版权声明

本文仅代表作者观点,不代表百度立场。
本文系作者授权百度百家发表,未经许可,不得转载。

热门文章
  • 机房智能化温湿度解决方式之POE供电以太网温湿度传感器

    机房智能化温湿度解决方式之POE供电以太网温湿度传感器
    机房智能化温湿度解决方式之POE供电以太网温湿度传感器 北京盈创力和电子科技有限公司 智能型TCP网口温湿度记录仪 北京IP网络温湿度记录仪厂家,北京盈创力和 北京智能型TCP网口温湿度记录仪IP网络温湿度记录仪是一种新型的基于TCP/IP协议双绞线以太网标准温湿度采集模块,利用它可以实现现场温度值、相对湿度值的采集,同时利用其自身的RJ45通信接口可以方便地和机房监控主机或交换机集线器进行联网。 工作于-40℃~85℃工业级带...
  • Sequential Monte Carlo Methods (SMC) 序列蒙特卡洛/粒子滤波/Bootstrap Filtering

    Sequential Monte Carlo Methods (SMC) 序列蒙特卡洛/粒子滤波/Bootstrap Filtering
    Problem Statement 我们考虑一个具有马尔可夫性质、非线性、非高斯的状态空间模型(State Space Model):对于一个时间序列上的观测结果{yt,t∈N}\\{ y_t , t \\in N \\}{yt​,t∈N},我们认为每个观测结果yty_tyt​的生成依赖于一个无法直接观察的隐变量xt∈{xt,t∈N}x_t \\in \\{x_t , t \\in N \\}xt​∈{xt​,t∈N},即:p(...
  • HTTP状态保持的原理

    HTTP状态保持的原理
    a)在用户登录之后,浏览器返回响应的时候会在响应中添加上cookieb)浏览器接收到cookie之后会自动保存c)当用户再次请求同一服务器中的其他网页的时候,浏览器会自动带上之前保存的cookied)服务接收到请求之后可以请 request 对象中取到cookie 判断当前用户是否登录  Http是无状态的,就是连接时数据互通,关闭后...
  • Hive 系统函数及示例

    Hive 系统函数及示例
    查看所有系统函数 show functions; 函数分类 内置函数【系统函数】 数学函数: floor、round、ceil、cos、log2等 字符串函数: length、reverse、trim、lower、get_json_object、repeat等 收集函数: size 转换函数: cast 日期函数: year、month、datediff、date、date_add等 条件函数: coalesce、case…w...
  • CSRF的原理和防范措施

    CSRF的原理和防范措施
    a)攻击原理:i.用户C访问正常网站A时进行登录,浏览器保存A的cookieii.用户C再访问攻击网站B,网站B上有某个隐藏的链接或者图片标签会自动请求网站A的URL地址,例如表单提交,传指定的参数iii.而攻击网站B在访问网站A的时候,浏览器会自动带上网站A的cookieiv.所以网站A在接收到请求之后可判断当前用户是登录状态,所以...
标签列表