拷贝构造函数-深cop与浅copy

一、直接初始化与拷贝初始化

在一个类对象的定义过程中,对象初始化分为两种:
1)、直接初始化, 要求编译器使用普通的函数匹配,选择我们提供的最匹配的 构造函数
2)、拷贝初始化, 要求编译器将右侧运算对象拷贝到正在创建的对象中,通常使用 拷贝构造函数 来完成。

//直接初始化,使用string的构造函数string (size_t n, char c);
string dots(10,'s';
//直接初始化,使用拷贝构造函数string (const string& str);
string s(dots);
//使用拷贝赋值运算符,拷贝初始化,使用拷贝构造函数string (const string& str);
string s1 = dots;
//拷贝初始化
string null_book = "9-99-999";
//拷贝初始化
string nines = string(10,'s');

二、拷贝构造函数-定义

在对象拷贝过程中,如果没有自定义拷贝构造函数,系统会提供一个缺省的拷贝构造函数,进行的是浅拷贝!
即使定义了其它构造函数,编译器也会合成一个拷贝构造函数,即合成拷贝构造函数。

class Foo{
public:
	Foo();				//默认构造函数
	Foo(const Foo&);	//拷贝构造函数
}

一个拷贝构造函数的构成:
1、一个构造函数的第一个参数是自身类型的引用
2、且任何额外参数都有默认值

拷贝初始化的使用场景:
1、将一个对象作为实参传递给一个非引用类型的形参

class Foo {
	int a;
	Foo* next;
public:
	Foo() = default;
	Foo(int p) :a(p), next(nullptr) {}
	Foo(int p, Foo* nex) :a(p), next(nex) {}
	Foo(const Foo& p) :a(p.a), next(p.next) {}
	
	~Foo() = default;

	void copy1(Foo s);
	void copy(Foo& s);
	
	Foo* out();
	Foo out2();
};
void Foo::copy1(Foo s) 	//实参到形参,调用拷贝构造函数
						//实参到形参发生的拷贝中,next是一次浅拷贝
						//next访问的仍是实参next指向的内存
{
	a = s.a;
	next = s.next;
}
void Foo::copy(Foo& s)	//只是引用,未调用拷贝构造函数
{
	a = s.a;
	next = s.next;
}

2、从一个返回类型为非引用类型的函数返回一个对象

Foo* Foo::out()	//返回的this指针赋值给新指针时,调用拷贝构造函数
{
	return this;
}
Foo Foo::out2()	//返回值会被赋值给一个对象,使用拷贝构造函数
{
	Foo ret(a);
	ret.next = new Foo(2);
	return ret;
}

3、用花括号列表初始化一个数组中的元素或一个聚合类中的成员

	Foo nin(9, six);	//使用构造函数,构造新对象
	Foo ten = {10,six};	//使用列表初始化格式对应的构造函数创建临时对象
						//再调用拷贝构造函数

三、深拷贝与浅拷贝

在定义拷贝构造函数时,会发生不同性质的拷贝过程,主要分为深拷贝和浅拷贝。

Foo(const Foo& p) :a(p.a), next(p.next) {}	//浅拷贝
Foo(const Foo& p)  	//深拷贝
	{
		a = p.a;
		next = new Foo();
		next ->a = p.next->a;
		next ->next = p.next ->next;
	}

其特点为:
浅拷贝只是对指针的拷贝,拷贝后两个指针指向同一个内存空间。
深拷贝不但对指针进行拷贝,而且对指针指向的内容进行拷贝,经深拷贝后的指针是指向两个不同地址的指针。

移动拷贝构造函数

可以支持移动操作,需要定义移动构造函数和移动赋值运算符。
会将给定对象的资源“窃取”,而不是拷贝资源。
一旦完成资源移动,源对象必须不在指向被移动的资源。

Foo(const Foo&& p) :a(p.a), next(p.next) 	//移动拷贝
{
	p.next = nullptr;	//这样释放p是安全的
}

该类类型的右值引用。

左值与右值的区别
左值持久,右值短暂
1、所引用的对象将要被销毁,字面值常量或者临时变量
2、该对象没有其它用户
左值是变量,右值不能被赋值

左值引用与右值引用
右值引用是为了支持移动操作,通过&&来获得右值引用。
右值引用可以自由接管所引用对象的资源。
C++11新特性:std::move(),可以将一个左值转换为对应的右值引用类型。

左值引用是相对于右值引用的,通过&来获得。
左值引用指向源对象的资源。
可以定义左值引用自己的写权限。
比如const引用就不可以修改源对象的值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值