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.函数返回只要是按值返回也调用拷贝构造函数。
2444

被折叠的 条评论
为什么被折叠?



