构造函数以及复制控制操作的调用时机

复制控制操作包括:复制构造函数、赋值操作符、析构函数;

以下两个例子给出构造函数和复制操作的调用时机。


复制构造函数可用于:

1)根据一个同类类型对象显示或隐式初始化一个对象;

2)复制一个对象,将其作为实参传递给一个函数;

3)从函数返回时复制一个对象;

4)初始化顺序容器中的元素;

5)根据元素初始化列表初始化数组元素。


例子一

class A {
	int data;
public:
	A() {
		cout << "\tA()" << endl;
	}

	A(const A & a) {
		data = a.data;
		cout << "\t复制构造函数" << endl;
	}

	A& operator=(const A& rhs) {
		cout << "\toperator=" << endl;
		return *this;
	}
};

A global;                     //调用构造函数

A foo(A arg) { 
	//调用复制构造函数,用arg初始化局部对象local
	cout << "2---------------" << endl;
	A local = arg;

	//这里是复制初始化方式:先调用指定构造函数创建临时对象,然后
	//用复制构造函数将临时对象复制到正在创建的对象。
	//但是编译器一般会优化,直接跳过复制构造函数直接创建对象,
	//所以这里并没有调用复制构造函数
	cout << "3---------------" << endl;
	A local2 = A();
	cout << "4---------------" << endl;

	//下面两句均调用复制构造函数
	A local3 = arg;
	A local4 = A(arg);
	local4 = arg;          //使用赋值操作符
	cout << "41--------------" << endl;
	A *heap = new A(global); //调用复制构造函数,根据全局对象global创建新的A对象
	cout << "5---------------" << endl;

	//这句没有调用(复制)构造函数,使用赋值操作符
	*heap = local;           
	cout << "6---------------" << endl;

	// 这里两次调用复制构造函数、两次调用默认构造函数
	// 如果没有为类类型数组提供元素初始化式,则将用默认构造函数初始化每个元素;
	// 如果使用常规的花括号括住数组初始化列表(如下)来显示初始化,则使用复制
	// 初始化来初始化每个元素。根据指定的值创建适当类型的元素,然后用复制构造函数
	// 将该值复制到相应元素。如下的数组使用花括号,因此使用复制构造函数来初始化。
    A pa[4] = {local, *heap};
	cout << "7---------------" << endl;

    /*
    如果是这样的定义,则只调用四次构造函数,不会调用复制构造函数
    A pa[4];   
	*/

	return *heap;            //调用复制构造函数,从函数返回A对象*heap的副本
}

int main() {
	cout << "A aa: "; 
	A aa;        //调用构造函数
	foo(aa);     //调用复制构造函数,复制一个对象,将其作为实参传递给一个函数

	cout << endl << "8----------------" << endl;

	//使用了五次默认构造函数和复制构造函数,先使用A的默认构造函数创建临时值
	//来初始化avec,然后使用复制构造函数将临时值复制到avec的每个元素。
	vector<A> avec(5);  
	return 0;
}

代码的github地址:https://github.com/liyangddd/cplusplus/blob/master/Call_constructor.cpp





例子二

class Exmpl {
public:
	Exmpl() {	cout << "Exmpl()" << endl;  }
	Exmpl(const Exmpl&) {  cout << "拷贝构造函数" << endl;  }
	Exmpl& operator= (const Exmpl & rhs) {
		cout << "oprator=" << endl;
		return *this;
	}
	~Exmpl() {  cout << "~Exmpl" << endl; }
};

void func1(Exmpl obj) {}   //形参为Exmpl对象
void func2(Exmpl& obj) {}  //形参为Exmpl对象的引用
Exmpl func3() {
	Exmpl obj;    return obj;
}

const Exmpl& func4(const Exmpl& obj) {
	return obj;
}
int main() {
	//调用默认构造函数创建Exmpl对象obj
	Exmpl obj;

	//调用复制构造函数
	//将形参Exmpl对象创建为实参Exmpl对象的副本
	//函数执行完毕后,调用析构函数撤销形参Exmpl对象
	func1(obj); 

	//形参为对象的引用,因此不需要调用复制构造函数传递实参
	func2(obj);

	//调用默认构造函数创建局部Exmpl对象
	//函数返回时调用复制构造函数创建作为返回值副本的Exmpl对象
	//然后调用析构函数撤销局部对象
	//调用赋值操作符完成赋值操作
	//调用析构函数撤销作为返回值副本的Exmpl对象
	obj = func3();

	//函数形参和返回值都是引用,不会调用(拷贝)构造函数
	func4(obj);

	//func4不会调用任何复制控制操作
	//由于exm也是一个引用,因此下一句不会调用任何构造、析构函数
	const Exmpl& exm = func4(obj);

	//调用拷贝构造函数来将exm2对象初始化为func4返回的对象的引用
	const Exmpl exm2 = func4(obj);

	//调用默认构造函数动态创建对象
	//该对象需要手动才能销毁
	Exmpl *p = new Exmpl;

	//三次调用默认构造函数创建临时对象
	//三次调用复制构造函数将临时对象复制到容器evec的每个元素
	//调用析构函数撤销临时对象
	vector<Exmpl> evec(3);
	
	//调用析构函数撤销动态创建的对象
	delete p;

	//evec和obj的生命结束,调用析构函数撤销
	//evec撤销需要调用三次析构函数
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值