C++ 拷贝构造函数 赋值构造函数

关键字:   C++    
 默认拷贝构造函数的行为如下:
 默认的拷贝构造函数执行的顺序与其他用户定义的构造函数相同,执行先父类后子类的构造.
 拷贝构造函数对类中每一个数据成员执行成员拷贝(memberwise Copy)的动作.
 a)如果数据成员为某一个类的实例,那么调用此类的拷贝构造函数.
 b)如果数据成员是一个数组,对数组的每一个执行按位拷贝.
 c)如果数据成员是一个数量,如int,double,那么调用系统内建的赋值运算符对其进行赋值.

 1.深拷与浅拷

 深拷贝和浅拷贝的定义可以简单理解成:如果一个类拥有资源(堆,或者是其它系统资源),当这个类的对象发生复制过程的时候(复制指针所指向的值),这个过程就可以叫做深拷贝,反之对象存在资源但复制过程并未复制资源(只复制了指针所指的地址)的情况视为浅拷贝。
  浅拷贝资源后在释放资源的时候会产生资源归属不清的情况导致程序运行出错,这点尤其需要注意!    
原则上,应该为所有包含动态分配成员的类都提供拷贝构造函数。

浅:

 

 

 

2 拷贝构造函数的另一种调用
当对象直接作为参数传给函数时,函数将建立对象的临时拷贝,这个拷贝过程也将调用拷贝构造函数。
例如:


 

程序输出:
载入构造函数:
载入构造函数:
载入拷贝构造函数
0载入拷贝构造函数
99
还有一种情况,也是与临时对象有关的。
当函数中的局部对象被用作返回值,返回给函数调用时,也将建立此局部对象的一个临时拷贝,此时拷贝构造函数也将被调用。——可是经测试发现情况有异。
代码如下:


 

程序输出:
载入构造函数:
n = 0
载入构造函数:
n = 100
载入构造函数:
n = 100
按理第2个和第3个应该输出'载入拷贝构造函数"才对,这个结果与预想的不一样,到底是哪里出问题了呢?
注:后来有论坛上的朋友告诉我说这是因为编译器的不同而导致不同的输出。
有人得到这样的输出结果:
载入构造函数
n = 0
载入构造函数
载入拷贝构造函数
n = 100
载入构造函数
载入拷贝构造函数
n = 100
还有人得到这样的输出结果:
载入构造函数
n = 0
载入构造函数
载入拷贝构造函数
n = 100
载入构造函数
载入拷贝构造函数
载入拷贝构造函数
n = 100
(用的是vc++)

3.3 无名对象
现在我们来说一下无名对象。什么是无名对象?利用无名对象初始化对象系统不会调用拷贝构造函数?这是我们需要回答的两个问题。  
首先我们来回答第一个问题。很简单,如果在程序的main函数中有:
  Internet ("中国");  //Internet表示一个类
这样的一句语句就会产生一个无名对象。
无名对象会调用构造函数,但利用无名对象初始化对象时系统不会调用拷贝构造函数!
下面的代码是常见的利用无名对象初始化对象的例子。


 

 

程序输出:
载入构造函数:
name的地址:  23ff40;name的字符串:  中国
cname的地址:  33778;cname的字符串:  中国
载入析构函数:

上面代码的运行结果有点“出人意料”,从思维逻辑上说,当无名对象创建了后,是应该调用自定义拷贝构造函数,或者是默认拷贝构造函数来完成复制过程的,但事实上系统并没有这么做,因为无名对象使用过后在整个程序中就失去了作用。对于这种情况c++会把代码看成是: Internet a ("中国");  省略了创建无名对象这一过程,所以说不会调用拷贝构造函数。

3.赋值符的重载
 由于并非所有的对象都会使用拷贝构造函数和赋值函数,程序员可能对这两个函数有些轻视。请先记住以下的警告,在阅读正文时就会多心:
本章开头讲过,如果不主动编写拷贝构造函数和赋值函数,编译器将以“位拷贝”的方式自动生成缺省的函数。倘若类中含有指针变量,那么这两个缺省的函数就隐含了错误。以类String的两个对象a,b为例,假设a.m_data的内容为“hello”,b.m_data的内容为“world”。
 现将a赋给b,缺省赋值函数的“位拷贝”意味着执行b.m_data = a.m_data。这将造成三个错误:一是b.m_data原有的内存没被释放,造成内存泄露;二是b.m_data和a.m_data指向同一块内存,a或b任何一方变动都会影响另一方;三是在对象被析构时,m_data被释放了两次。
拷贝构造函数和赋值函数非常容易混淆,常导致错写、错用。拷贝构造函数是在对象被创建时调用的,而赋值函数只能被已经存在了的对象调用。以下程序中,第三个语句和第四个语句很相似,你分得清楚哪个调用了拷贝构造函数,哪个调用了赋值函数吗?
String  a(“hello”);
String  b(“world”);
String  c = a; // 调用了拷贝构造函数,最好写成 c(a);
 c = b;  // 调用了赋值函数
本例中第三个语句的风格较差,宜改写成String c(a) 以区别于第四个语句。
请看下面的代码:

 

 

 

程序输出:
载入构造函数:
3-1-6
载入拷贝构造函数
载入赋值函数
3-1-6
载入构造函数:
0-0-0
载入赋值函数
3-1-6
请注意:程序输出了两次“载入赋值函数”,这是因为我们在拷贝构造函数中使用了赋值函数,这样使程序变得简洁。如果把拷贝构造函数改写为:
Date::Date(const Date &other)
{
 cout << "载入拷贝构造函数" << endl; 
 da = other.da;
 mo = other.mo;
 yr = other.yr;
}
则程序将输出:
载入构造函数:
3-1-6
载入拷贝构造函数
3-1-6
载入构造函数:
0-0-0
载入赋值函数
3-1-6

6. 偷懒的办法处理拷贝构造函数和赋值函数
 如果我们实在不想编写拷贝构造函数和赋值函数,又不允许别人使用编译器生成的缺省函数,怎么办?
 偷懒的办法是:只需将拷贝构造函数和赋值函数声明为私有函数,不用编写代码。
 例如:
 class A
 { …
   private:
  A(const A &a);    // 私有的拷贝构造函数
  A & operator =(const A &a); // 私有的赋值函数
 };
 
 如果有人试图编写如下程序:
 A  b(a); // 调用了私有的拷贝构造函数
 b = a;  // 调用了私有的赋值函数
编译器将指出错误,因为外界不可以操作A的私有函数。(引自〈〈高质量c++编程指南〉〉)
 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
拷贝构造函数是用来创建一个新对象并将其初始化为给定对象的副本的特殊成员函数。它通常用于以下情况: - 当一个对象通过值传递给函数或以值的形式返回时 - 当一个对象用另一个对象进行初始化时 - 当一个对象作为另一个对象的成员进行初始化时 对于类`Person`的拷贝构造函数,它会接受一个`const Person&`类型的参数,并将其成员变量`name_`赋值给新创建的对象的`name_`成员变量。 赋值运算符是用于将一个对象的值分配给另一个已经存在的对象的成员函数。它通常用于以下情况: - 当一个对象被另一个对象赋值时 - 当一个对象作为另一个对象的成员进行赋值时 对于类`Person`的赋值运算符,它会接受一个`const Person&`类型的参数,并将其成员变量`name_`赋值给当前对象的`name_`成员变量。然后,它将返回一个指向左侧运算对象的引用,以支持连续赋值的操作。 如果在类定义中没有显式定义拷贝构造函数赋值运算符,编译器会为类生成默认的拷贝构造函数赋值运算符。此外,我们还可以使用`=default`来显式要求编译器生成合成的拷贝构造函数赋值运算符。这将使用默认的实现来完成拷贝和赋值操作。 总之,拷贝构造函数用于创建一个对象的副本,而赋值运算符用于将一个对象的值赋给另一个已经存在的对象。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [C++拷贝构造函数与拷贝赋值运算符](https://blog.csdn.net/xiongya8888/article/details/89424224)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值