为什么要引入拷贝构造函数?(提出问题)

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

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

拷贝赋值函数:对象已经存在不用创建 + 用一个已经存在的对象进行初始化(区分开初始化操作和赋值)

举例: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)函数的形参是类的对象 +  参数使用值传递(参数为引用的时候不调用拷贝构造函数),传参时,会调用拷贝构造函数

fun1(Coord p)
{
函数体
}
调用语句:
Coord p1;
fun1(p1);
//分析:调用拷贝构造函数 Coord p=p1; fun1(Coord& p)
{
函数体
}
调用语句:
Coord p1;
fun1(p1);

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

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

Coord fun1(Coord& fun)
{
return fun;
} 调用语句:
Coord c;
Coord p=fun(c);

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

Coord& fun1(Coord& fun1)
{
return fun1;
} 调用语句:
Coord c;
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返回即可

怎么使用拷贝构造函数?

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

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

{拷贝成员}

代码:

class Point
{
public:
Point(int xx=,int yy=){X=xx; Y=yy;}
Point(Point& p);
private:
int X,Y;
};
Point::Point (Point& p)
{
X=p.X; //参数p可以直接引用私有变量
Y=p.Y;
}

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

常见问题:

1、为什么拷贝函数的参数必须是引用?(拷贝构造函数的参数必须是对象的引用)

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

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

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

2、浅拷贝与深拷贝

出现这个问题的原因:构造函数中需要为指针申请空间

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

浅拷贝:在拷贝构造函数中,仅仅使用成员间的对应复制,两个对象的指针的都指向同一个空间,一个指针指向的空间被释放,再用另一个指针去访问被释放掉的空间,将会导致程序崩溃。

解决方法:如果构造函数需要为类显示申请空间(含指针,使用new),则要使用显式的拷贝构造函数,如果类中成员都是非指针,则可以使用系统默认的拷贝构造函数。

浅拷贝代码

  

#include <iostream>
#include <string>
using namespace std;
class Point
{
private:
char * name;
public:
Point(char * className)
{
name = new char[strlen(className)+];
strcpy(name, className);
}
Point(Point& p)//浅拷贝,或者不写
{
name = p.name;//(系统默认拷贝函数执行的代码)
}
~Point()
{
cout<<name<<endl;//测试关键语句
delete []name;
}
}; int main()
{
Point a("");
Point b=a;
return ;
}

深拷贝:

#include <iostream>
#include <string>
using namespace std;
class Point
{
private:
char * name;
public:
Point(char * className)
{
name = new char[strlen(className)+];
strcpy(name, className);
}
Point(Point& p)//深拷贝
{
name = new char[strlen(p.name)+];
strcpy(name,p.name);
}
~Point()
{
cout<<name<<endl;
delete []name;
}
}; int main()
{
Point a("");
Point b=a;
return ;
}

C++之拷贝构造函数的更多相关文章

  1. C++ 拷贝构造函数和赋值运算符

    本文主要介绍了拷贝构造函数和赋值运算符的区别,以及在什么时候调用拷贝构造函数.什么情况下调用赋值运算符.最后,简单的分析了下深拷贝和浅拷贝的问题. 拷贝构造函数和赋值运算符 在默认情况下(用户没有定义 ...

  2. C++ 一个例子彻底搞清楚拷贝构造函数和赋值运算符重载的区别

    class TestChild { public: TestChild() { x=; y=; printf("TestChild: Constructor be called!\n&quo ...

  3. C++ 为什么拷贝构造函数参数必须为引用?赋值构造函数参数也必须为引用吗?

    之前写拷贝构造函数的时候,以为参数为引用,不为值传递,仅仅是为了减少一次内存拷贝.然而今天看到一篇文章发现自己对拷贝构造的参数理解有误. 参数为引用,不为值传递是为了防止拷贝构造函数的无限递归,最终导 ...

  4. C++拷贝构造函数

    拷贝构造函数是一种特殊的构造函数,其定义为第一个参数为为本类型的一个引用或者是常引用,且无其它参数或者其它参数为默认值,例如下面的函数: X::X(const X&); X::X(X& ...

  5. PoEdu - C++阶段班【Po学校】- Lesson03-4_构造函数&赋值函数&拷贝构造函数&学习方式 - 第6天

    PoEdu - C++阶段班[Po学校]- 第6天 课堂选择题目: 1  关于转换构造函数  ClassDemo demo = 1;  调用转换构造函数 2  关于拷贝赋值函数  demo =2; 首 ...

  6. C++拷贝构造函数(深拷贝,浅拷贝)

    对于普通类型的对象来说,它们之间的复制是很简单的,例如:int a=88;int b=a; 而类对象与普通对象不同,类对象内部结构一般较为复杂,存在各种成员变量.下面看一个类对象拷贝的简单例子. #i ...

  7. C++ 拷贝构造函数 和 六大函数

    1.  C++什么时候会调用 拷贝构造函数? a.一个对象作为函数参数,以值传递的方式传入函数体: b.一个对象作为函数返回值,以值传递的方式从函数返回:(实际使用时,会被编译器优化掉) c.一个对象 ...

  8. 一个CString的实现 拷贝构造函数的应用

    class CString { public: CString (char* s); CString(); ~CString(); private: char *str; int len; stati ...

  9. 【转】C++的拷贝构造函数深度解读,值得一看

    建议看原帖  地址:http://blog.csdn.net/lwbeyond/article/details/6202256 一. 什么是拷贝构造函数 首先对于普通类型的对象来说,它们之间的复制是很 ...

  10. C++拷贝构造函数(深拷贝,浅拷贝)

    http://www.cnblogs.com/BlueTzar/articles/1223313.html 对于普通类型的对象来说,它们之间的复制是很简单的,例如:int a=88;int b=a;  ...

随机推荐

  1. Java String.format 自动补全不够的位数

    http://www.blogjava.net/java-blog/articles/189040.html

  2. 如何在ASP.NET 项目中使用Silverlight页面

    闲来无事,想写个网站玩玩,比较懒,不想写太多的样式来美化,看中了Silverlight,样式布局比较省事,但是又不想全部都用Silverlight 来写,所以才有此一文. 其实Silverlight最 ...

  3. Function.prototype.apply()

    文章地址:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply ...

  4. 关于Java中的选择排序法和冒泡排序法

    一,这种方法是直接传入一个数组进行排序(选择排序法) public static void selectSort(int arr[]){ for (int i = 0; i < arr.leng ...

  5. 对有状态bean和无状态bean的理解(转)

    现实中,很多朋友对两种session bean存在误解,认为有状态是实例一直存在,保存每次调用后的状态,并对下一次调用起作用,而认为无状态是每次调用实例化一次,不保留用户信息.仔细分析并用实践检验后, ...

  6. 利用c++操作XML,主要是内部循环方法的使用

    本文主要分享的是循环方法的使用,设置XML节点属性,用了3种循环方法. XML文件: <?xml version='1.0' encoding='utf-8' ?><root> ...

  7. CANoe 入门 Step by step系列(二)CAPL编程【转】

    CAPL就是Communication Application Programming Laguage的缩写,CAPL类似于C语言的语法,因此所有的语法请参考C语言教程,这里不在这里进行详述,关于C语 ...

  8. OC语言-02面向对象的三大特性

    01封装 #import <Foundation/Foundation.h> @interface Student : NSObject { //@public 成员变量尽量不使用 int ...

  9. CentOS 6.0 图文安装教程

    CentOS 6.0下载地址:wget http://ftp.riken.jp/Linux/centos/6.0/isos/i386/CentOS-6.0-i386-bin-DVD.iso 下边就是安 ...

  10. PAT (Basic Level) 1001害死人不偿命的(3n+1)猜想 (15)

    卡拉兹(Callatz)猜想: 对任何一个自然数n,如果它是偶数,那么把它砍掉一半:如果它是奇数,那么把(3n+1)砍掉一半.这样一直反复砍下去,最后一定在某一步得到n=1.卡拉兹在1950年的世界数 ...