C++学习笔记35——复制构造函数

1,复制构造函数综述

复制构造函数(copy constructor)是构造函数的一种,用于将新对象 初始化为另一同类型对象的副本的构造函数。
复制构造函数的(唯一)形参是本类类型对象的引用,且常用const限定。
 
注意复制与赋值的区别:
对象的赋值是对一个已存在的对象赋值,因此必须先定义被赋值的对象,才能进行赋值。而对象的复制则是从无到有地建立一个新对象,并使它与一个已有的对象完全相同(包括对象的结构和成员的值),类似于克隆。

 

2,调用复制构造函数的情形

1,根据另一个同类型的对象显式或隐式初始化一个对象(使用等号和使用括号,哪个是显式哪个是隐式?反正调用的都是复制构造函数)
2,复制一个对象,将它作为实参传给一个函数(即函数输入参数为类类型,且不是引用)
3,从函数返回时复制一个对象(即函数的返回类型为类类型, 且不是引用)
4,初始化顺序容器中的元素
C<T> c(n)  调用n次默认构造函数
C<T> c(n,t)调用n次复制构造函数
5,根据元素初始化列表,初始化数组元素
举例如下:
class People
{
public:
	People() :name("nobody"), age(0) {}//默认构造函数
	People(string new_name, int new_age) :name(new_name), age(new_age){}//一般构造函数
	People(const People &new_People);//声明自己的复制构造函数
	inline void show()const;//普通成员函数

private:
	string name;
	unsigned  age;
};

//复制构造函数的定义
People::People(const People &new_People)
{
	// 把元素逐一复制
	name = new_People.name;
	age  = new_People.age;

	// 尝试另一种写法
	//*this = new_People; //这种写法实际上是用了赋值操作符,不应该用这种写法

	cout << "calling the copy constructor." << endl;
}

void People::show() const
{
	cout <<"People的成员函数show内:"<< name << ": " << age << endl;
	return;
}

int main()
{
	/*******************************************************************/
	//     复制构造函数
	/*******************************************************************/
	People HY("HuangYang", 27);
	People WHY("WangHaiyan", 26);

	// 1,初始化另一个对象
	cout << "复制出另外两个对象" << endl;
	People Myself(HY); //说好的直接初始化呢?
	People You = WHY;

	// 2.1,作为实参传递给函数和从函数返回
	cout << "\n\n" << "调用show_info()" << endl;
	show_info(HY);

	// 2.2,使用引用类型时,不调用复制构造函数
	cout << "\n\n" << "调用show_info_ref()" << endl;
	show_info_ref(Myself);

	// 3,初始化顺序容器
	cout << "\n\n" << "创建含有5个Peple的容器" << endl;
	vector<People> group(5,HY);
	
	cout << "\n\n" << "创建含有3个没有指定值的Peple的容器" << endl;
	vector<People> group_2(3);

	// 4,用元素初始化列表初始化数组
	cout << "\n\n" << "创建含有2个Peple的数组" << endl;
	People us[2] = {HY,WHY};
	
	system("pause");
	return 0;
}

 
最终输出为:

3,合成的复制构造函数

如果我们定义了自己的构造函数,编译器就不会再合成默认构造函数;
但是即便我们定义了构造函数,编译器也还是会合成复制构造函数,除非我们定义自己的复制构造函数。
 
合成复制构造函数的行为是执行逐个成员初始化,编译器依次复制对象的每个 非static成员。如果存在数组成员,则数组里的每个元素都会复制过去。
 
如果数据成员为引用类型,那么合成的复制构造函数会使得两个对应的引用绑定到同一个对象。指针类型也是如此。示例如下:
#include <iostream>
using std::cout;
using std::endl;

class A {
public:
	A() : x1(3), x2(x1){}
 
	int x1;
	int &x2;
};
 
int main()
{
	A a;
	A b = a;

	cout << "\n打印地址"<< endl;
	cout << "&a.x1=" << &a.x1 << "  &a.x2=" << &a.x2 << endl;
	cout << "&b.x1=" << &b.x1 << "  &b.x2=" << &b.x2 << endl;
} 

执行的结果如下:

打印地址
&a.x1=0x7ffc81aaf0a0  &a.x2=0x7ffc81aaf0a0
&b.x1=0x7ffc81aaf0b0  &b.x2=0x7ffc81aaf0a0

结果表明,a.x1、a.x2、b.x2这3个成员有相同的地址。

4,定义自己的复制构造函数

在例子中我们已经定义了一个自己的复制构造函数,让它除了实现复制的功能外还打印了一句话,以证明确实在调用复制构造函数。
必须定义自己的复制构造函数的情形:
1,数据成员里有指针;
2,构造函数中需要分配内存;
3,执行某些特定工作(比如打印一句话?);

5,禁止复制

将复制构造函数设为私有,则复制构造函数就无法调用。
如果要连友元和成员中的复制也禁止,则必须声明一个private的复制构造函数但并不对其进行定义。
 
注意:复制构造函数也是构造函数,如果定义了自己的复制构造函数,编译器就不会合成默认构造函数了。所以一般定义了复制构造函数也就需要自己定义默认构造函数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值