C++什么时候调用拷贝构造函数、赋值运算符

class Person
{
public:

    Person(const Person& p);    //拷贝构造函数

    Person& operator=(const Person& p);   //赋值运算符重载

private:
    int age;
    string name;
};

何时调用

拷贝构造函数和赋值运算符的行为比较相似,都是将一个对象的值复制给另一个对象;但是其结果却有些不同,

拷贝构造函数使用传入对象的值生成一个新的对象的实例,而赋值运算符是将对象的值复制给一个已经存在的实例

这种区别从两者的名字也可以很轻易的分辨出来,拷贝构造函数也是一种构造函数,那么它的功能就是创建一个新的对象实例;赋值运算符是执行某种运算,将一个对象的值复制给一个已经存在的实例

调用的是拷贝构造函数还是赋值运算符,主要是看是否有新的对象实例产生。如果产生了新的对象实例,那调用的就是拷贝构造函数;如果没有,那就是对已有的对象赋值,调用的是赋值运算符。

 

拷贝构造函数调用时机主要有以下场景:

  • 对象作为函数的参数,以值传递的方式传给函数。 
  • 对象作为函数的返回值,以值的方式从函数返回
  • 使用一个对象给另一个对象初始化

 

范例

#include <iostream>
using namespace std;
 
//定义一个Point类
class Point{
public:
	Point(int xx=0,int yy=0):x(xx),y(yy){}     //构造函数
	~Point(){ };                              //析构函数
    Point(const Point &p);                //拷贝构造函数 的声明
	int getX()const{return x;}
	int getY()const {return y;}
private:
	int x,y;//私有成员
 
};

//拷贝构造函数 的定义
Point::Point(const Point &p)   
{
	x = p.x;
	y = p.y;
	cout << "Calling the copy constructor" <<endl;
 
}

//形参作为Point类对象的函数
void fun1(Point p)
{
	cout<< p.getX()<<endl;
 
}
 
//返回类的对象
Point fun2()
{
	Point a(1,2);
	return a;
}
 
int main()
{
	Point a(4);    //第一个对象A,该过程利用了重载,后面的y默认为0
	
	Point b(a);      //此时调用拷贝构造函数;情况1,用a初始化b,第一次调用拷贝构造函数
	cout << b.getX()<<endl; 
 
	fun1(b);  //此时调用拷贝构造函数;类的对象在函数中为实参,第二次调用拷贝构造函数
 
	b = fun2();//此时调用拷贝构造函数;函数返回值为类的对象,第三次调用拷贝构造函数
	cout << b.getX()<<endl; 
	return 0;
}

 

为了更好地理解拷贝构造函数   
 1、为什么要有拷贝构造函数,它跟构造函数有什么区别?
       答:拷贝构造函数其实也是构造函数,只不过它的参数是const 的类自身的对象的引用。如果类里面没有指针成员(该指针成员指向动态申请的空间),是没有必要编写拷贝构造函数的 。     我们知道,如果有一个类CObj,它已经产生了一个对象ObjA,现在又用CObj去创建ObjB,如果程序中使用语句ObjB = ObjA; 也就是说直接使用ObjA的数据给ObjB赋值。这对于一般的类,没有任何问题,但是如果CObj里面有个char * pStr的成员,用来存放动态申请的字符串的地址,在ObjA中使用new 方法动态申请了内存并让ObjA.pStr指向该申请的空间,在OjbB = OjbA之后,ObjA.pStr和ObjB.pStr将同时指向那片空间,这样到导致了谁也不知道到底该由谁来负责释放那块空间,很有可能导致同一块内存被释放两次。     使用拷贝构造函数,先申请ObjA.pStr所指向的空间大小的空间,然后将空间内容拷贝过来,这样就不会同时指向同一块内存,各自有各自申请的内存,各自负责释放各自申请的内存,从而解决了刚才的问题。所以这里的“拷贝”拷贝的是动态申请的空间的内容,而不是类本身的数据。另外注意到,拷贝构造函数的参数是对象的引用,而不是对象的指针。至于为什么要用引用,不能够用指针暂时还没有搞明白,等搞明白了再说。    
2、为什么要对=赋值操作符进行重载?
    答:接上面的例子,用户在使用语句ObjB = ObjA的时候,或许ObjB的pStr已经指向了动态申请的空间,如果直接简单将其指向的地址覆盖,就会导致内存泄露,所以需要对=赋值操作符进行重载,在重载函数中判断pStr如果已经指向了动态申请的空间,就先将其释放。    
3、拷贝构造函数和=赋值操作符重载的关系。
    答:从原文的例子中可以看出,=赋值操作符重载比拷贝构造函数做得要多,它除了完成拷贝构造函数所完成的拷贝动态申请的内存的数据之外,还释放了原本自己申请的内存空间。所以原文最后给出的拷贝构造函数的实现可以使用=赋值操作符的重载来完成。    
4、拷贝构造函数何时被调用?
    a.对象的直接赋值也会调用拷贝构造函数  ;
    b.函数参数传递只要是按值传递也调用拷贝构造函数;
    c.函数返回只要是按值返回也调用拷贝构造函数。

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值