C++拷贝构造函数使用



C++拷贝构造函数,为什么要引入与使用拷贝构造函数?

       作用:创建一个对象的同时,使用一个已经存在的对象给另一个对象赋值

具体来说:它将一个已经定义过对象的数据成员 逐一拷贝给 新对象,而产生两个完全相同的内存拷贝

做比较:拷贝构造函数:对象被创建 +  用一个已经存在的对象进行初始化

拷贝赋值函数:对象已经存在不用创建 + 用一个已经存在的对象进行初始化

举例:string a(“hello”);//调用构造函数

string b(“would”);//调用构造函数

string c=a;//调用拷贝构造函数–风格差,应使用string c(a)

c=b;//调用拷贝赋值函数

什么时候使用拷贝构造函数?(系统自己调用)

在创建新对象的时候,希望将一个已经存在的对象拷贝给这个新对象,这时系统会自动调用拷贝构造函数

总结:1、拷贝构造函数的参数必须是引用,否则出错。

2、执行的语句类似 Coord p=p1; 则会调用拷贝构造函数

有三种情况:

1)创建一个新类 +  并使用类的一个对象初始化该类的另一个对象

Coord p2(p1);//用对象p1初始化对象p2

Coord p3=p1;//用对象p1初始化对象p1

2)函数的形参是类的对象 +  参数使用值传递(参数为引用的时候不调用拷贝构造函数),传参时,会调用拷贝构造函数

  1. fun1(Coord p)
  2. {
  3.     函数体
  4. }
  5. 调用语句:
  6. Coord p1;
  7. fun1(p1);
  8. //分析:调用拷贝构造函数 Coord p=p1;
  9. fun1(Coord& p)
  10. {
  11.     函数体
  12. }
  13. 调用语句:
  14. Coord p1;
  15. fun1(p1);

//分析:参数表中使用了引用,没有调用拷贝构造函数啊,执行 Coord& p=p1;

3)函数的返回值是对象,函数调用完毕,返回调用者时,会调用拷贝构造函数

  1. Coord fun1(Coord& fun)
  2. {
  3.     return fun;
  4. }
  5. 调用语句:
  6. Coord  c;
  7. Coord p=fun(c);

//分析:return fun调用两次拷贝构造函数; VC测试,但是VS2005只调用一次,应该是进行了优化

  1. Coord& fun1(Coord& fun1)
  2. {
  3.     return fun1;
  4. }
  5. 调用语句:
  6. Coord  c;
  7. Coord p=fun1(c);

// 分析:Coord p=fun1(c)调用一次拷贝构造函数,因为最后使用返回函数引用,return时没有借助临时变量,直接是 Coord p=fun1;
出现这种现象的原因:

1、在使用return返回一个对象时,系统是先申请一个临时对象temp,执行Coord temp=fun1;(调用一次拷贝构造函数)

之后在执行Coord p=temp;(第二次调用)

2、在使用返回函数引用时,系统不会申请临时对象,只是直接把fun1拷贝给p

即直接执行Coord p=fun1,而没有引入temp,故少用一次拷贝构造函数


注意:这时要注意一个常出现的错误,返回的值不能是一个临时变量,常常的解决办法是函数参数使用引用,之后在使用return返回即可

怎么使用拷贝构造函数?

语法:函数名与类名相同,参数为本对象的引用,无返回类型,只有一个

类名::类名(类名& 对象名)

{拷贝成员}

代码:

  1. class Point
  2. {
  3. public:
  4.     Point(int xx=0,int yy=0){X=xx; Y=yy;}
  5.     Point(Point&  p);
  6. private:
  7.     int  X,Y;
  8. };
  9. Point::Point (Point& p)
  10. {
  11.     X=p.X; //参数p可以直接引用私有变量
  12.     Y=p.Y;
  13. }

注意:参数必须为本对象的引用 + 函数体内参数可以直接引用私有变量(老忘)

常见问题:

1、为什么拷贝函数的参数必须是引用?

简单点说,为了避免递归。

具体来说,引用传递的时候不需要调用拷贝构造函数 而 值传递需要调用拷贝构造函数

所以,在进入拷贝构造函数时,需要把对象传进来,这时使用值传递还要再调一次拷贝构造函数…..这时要无限传递下去

2、浅拷贝与深拷贝

出现这个问题的原因:构造函数中需要为指针申请空间(简单点说,成员变量含有指针)

深拷贝:在拷贝构造函数中,为指针显式申请空间(正确的方式)

浅拷贝:在拷贝构造函数中,仅仅使用成员间的对应复制,两个对象的指针的都指向同一个空间,一个指针指向的空间释放,另一个指针为野指针,危害江湖。

解决方法:如果构造函数需要为类显示申请空间(含指针,使用new),则要使用显式的拷贝构造函数

如果类中成员都是非指针,则可以使用系统默认的拷贝构造函数。

浅拷贝代码

  1. #include <iostream>
  2. #include <string>
  3. using namespace std;
  4. class Point
  5. {
  6. private:
  7.     char * name;
  8. public:
  9.     Point(char * className)
  10.     {
  11.         name = new char[strlen(className)+1];
  12.         strcpy(name, className);
  13.     }
  14.     Point(Point& p)//浅拷贝,或者不写
  15.     {
  16.         name = p.name;//(系统默认拷贝函数执行的代码)
  17.     }
  18.     ~Point()
  19.     {
  20.         cout<<name<<endl;//测试关键语句
  21.         delete []name;
  22.     }
  23. };
  24. int main()
  25. {
  26.     Point a(“123″);
  27.     Point b=a;
  28.     return 0;
  29. }

结果:

 

 

 

深拷贝:

  1. #include <iostream>
  2. #include <string>
  3. using namespace std;
  4. class Point
  5. {
  6. private:
  7.     char * name;
  8. public:
  9.     Point(char * className)
  10.     {
  11.         name = new char[strlen(className)+1];
  12.         strcpy(name, className);
  13.     }
  14.     Point(Point& p)//深拷贝
  15.     {
  16.         name = new char[strlen(p.name)+1];
  17.         strcpy(name,p.name);
  18.     }
  19.     ~Point()
  20.     {
  21.         cout<<name<<endl;
  22.         delete []name;
  23.     }
  24. };
  25. int main()
  26. {
  27.     Point a(“123″);
  28.     Point b=a;
  29.     return 0;
  30. }

结果: