构造函数
是一种特殊的方法 主要用来在创建对象时初始化对象 即为对象成员变量赋初始值.一个类也可以有多个构造函数,用来初始化不同形式的类。
构造函数被调用通常发生在以下三种情况,
第一种情况就是用一个对象初始化另一个对象时;
第二种情况是当对象作函数参数,实参传给形参时;
第三种情况是程序运行过程中创建其它临时对象时
拷贝构造函数
是特殊的构造函数,用来完成对象初始化,即定义时赋值,下面程序中有详解。如果没有定义,系统会调用默认的拷贝构造函数,但此函数不能处理深拷贝问题,及若有new用到,系统的只是共享区域,不分配新空间。
在C++中,下面三种对象需要拷贝的情况。因此,拷贝构造函数将会被调用。 1). 一个对象以值传递的方式传入函数体 2). 一个对象以值传递的方式从函数返回 3). 一个对象需要通过另外一个对象进行初始化 
举四个栗子:
stringOwn str1(strOrigin);
stringOwn str1 =  strOrigin;
stringOwn str1 = stringOwn (strOrigin);
stringOwn * pstr1 = new stringOwn(strOrigin);
stringOwn * pstr1 = FuncStringOwnReturn(va1, val2);
BOOL bResult = FuncStringOwnIn(stringown1 , val2);
赋值函数
要用运算符重载来实现。下面有程序。
来源: <http://zhidao.baidu.com/link?url=9tY333xKVwdUpvkS6yvhiJsyHs7tizzncfsbVxUXJ5NbVExSF7GSkCBYJiRyqDFJEDUN6ZBFQLDp94ukjsMe1_>
 
#include <iostream>
using namespace std;
class time
{public:time() //constructor.构造函数{hour=0;minute=0;sec=0;}time(const time &obj)  //拷贝构造函数{hour = obj.hour;minute = obj.minute;sec = obj.sec;}time& operator=(const time &obj)  //运算符重载,用来完成赋值函数{this->hour = obj.hour;this->minute = obj.minute;this->sec = obj.sec;return *this;}void set_time();void show_time();private:int hour;int minute;int sec;
};
int main()
{class time t1;  //调用time()构造函数为成员赋初值t1.show_time();time t2 = t1;   //调用拷贝构造函数,为对象t2赋值t2.show_time();time t3;t3 = t1;  //调用运算符重载=函数,为对象t3赋值t3.show_time();return 0;
}
void time::show_time()
{ cout<<hour<<":"<<minute<<":"<<sec<<endl;
}

如果不主动编写拷贝构造函数赋值函数,编译器将以“位拷贝”的方式自动生成缺省的函数。倘若类中含有指针变量,那么这两个缺省的函数就隐含了错误。以类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 被释放了两次
拷贝构造函数和赋值函数非常容易混淆,常导致错写、错用。拷贝构造函数是在对象被创建时调用的,而赋值函数只能被已经存在了的对象调用。
    CTemp a(b); //拷贝构造函数,C++风格的初始化CTemp a=b; //仍然是拷贝构造函数,不过这种风格只是为了与C兼容,与上面的效果一样,在这之前a不存在,或者说还未构造好。CTemp a;a=b; //赋值运算符在这之前a已经通过默认构造函数构造完成。
类String 的拷贝构造函数与赋值函数  // 拷贝构造函数  
    String::String(const String &other){// 允许操作other 的私有成员m_dataint length = strlen(other.m_data);m_data = new char[length+1];strcpy(m_data, other.m_data);}// 赋值函数String & String::operator =(const String &other){// (1) 检查自赋值if(this == &other)return *this;// (2) 释放原有的内存资源delete [] m_data;// (3)分配新的内存资源,并复制内容int length = strlen(other.m_data);m_data = new char[length+1];strcpy(m_data, other.m_data);// (4)返回本对象的引用return *this;}
         类String 拷贝构造函数与普通构造函数的区别是:在函数入口处无需与NULL 进行比较。
       类String 的赋值函数比构造函数复杂得多,分四步实现:
  (1)第一步,检查自赋值。你可能会认为多此一举,难道有人会愚蠢到写出 a = a 这样的自赋值语句!的确不会。但是间接的自赋值仍有可能出现,例如
  // 内容自赋值
  

    b = a;…c = b;…a = c;// 地址自赋值b = &a;…a = *b;

  也许有人会说:“即使出现自赋值,我也可以不理睬,大不了化点时间让对象复制自己而已,反正不会出错!”他真的说错了 。看看第二步的delete,自杀后还能复制自己吗 ?所以,如果发现自赋值,应该马上终止函数。注意不要将检查自赋值的if 语句
  

if(this == &other)

  错写成为

if( *this == other)

  (2)第二步, 用delete 释放原有的内存资源。如果现在不释放,以后就没机会了,将造成内存泄露。
  (3)第三步,分配新的内存资源,并复制字符串。注意函数strlen 返回的是有效字符串长度,不包含结束符‘\0’。函数strcpy 则连‘\0’一起复制。
  (4)第四步,返回本对象的引用,目的是为了实现象 a = b = c 这样的链式表达。注意不要将 return *this 错写成 return this 。那么能否写成return other 呢?效果不是一样吗?不可以!因为我们不知道参数other 的生命期。有可能other 是个临时对象,在赋值结束后它马上消失,那么return other 返回的将是垃圾。
  偷懒的办法处理拷贝构造函数与赋值函数
  如果我们实在不想编写拷贝构造函数和赋值函数,又不允许别人使用编译器生成的缺省函数,怎么办?
   偷懒的办法是:只需将拷贝构造函数和赋值函数声明为私有函数,不用编写代码。
  例如:
  

    class A{ …private:A(const A &a); // 私有的拷贝构造函数A & operator =(const A &a); // 私有的赋值函数};

  如果有人试图编写如下程序:
  

    A b(a); // 调用了私有的拷贝构造函数b = a; // 调用了私有的赋值函数

  编译器将指出错误,因为外界不可以操作A 的私有函数

拷贝构造函数是构造函数,不返回值   
   而赋值函数需要返回一个对象自身的引用,以便赋值之后的操作

一般来说是在数据成员包含指针对象的时候,应付两种不同的处理需求的 一种是复制指针对象,一种是引用指针对象 copy大多数情况下是复制,=则是引用对象的     
来源: <http://blog.chinaunix.net/uid-25808509-id-354211.html>

拷贝中的深拷贝和浅拷贝

简单的来说就是,在有指针的情况下,浅拷贝只是增加了一个指针指向已经存在的内存,而深拷贝就是增加一个指针并且申请一个新的内存使这个增加的指针指向这个新的内存,采用深拷贝的情况下,释放内存的时候就不会出现在浅拷贝时重复释放同一内存的错误!
在未重载‘=’运算符时,拷贝使用系统默认的无参拷贝函数,该函数是浅拷贝,必须重载运算符重新分配地址才是深拷贝。
我列举一个例子来说吧:
你正在编写C++程序中有时用到,操作符的重载。最能体现深层拷贝与浅层拷贝的,就是‘=’的重载。
看下面一个简单的程序:
class string
{char *m_str;public:string(char *s){m_str=s;}string(){};String & operator=(const string s){m_str=s.m_str;return *this}
};int main()
{string s1("abc"),s2;s2=s1;cout<<s2.m_str;
}
上面的 =重载其是就是实现了浅拷贝原因。是由于对象之中含有指针数据类型.s1,s2恰好指向同一各内存。所以是浅拷贝。而你如果修改一下原来的程序:
string&operator=(const string&s)
{if(strlen(m_str)!=strlen(s.m_str))m_str=new char[strlen(s.m_str)+1];if(*this!=s)strcopy(m_str,s.m_str);return *this;
}
这样你就实现了深拷贝,原因是你为被赋值对象申请了一个新的内存所以就是深拷贝
来源: <http://zhidao.baidu.com/link?url=hdipuGmK78oe8PGISXF9BlPS9PAGK0mSyh4kbyMbArwAFs1VBxACmazVze8aDPI3DxoGcoU17P62gKR85UkLZ_>

C++中拷贝构造、赋值构造的区别相关推荐

  1. 【C++】拷贝,赋值与构造

    拷贝,赋值与构造 文章目录 拷贝,赋值与构造 1. 拷贝构造函数/合成拷贝构造函数(copy constructor) 2. 拷贝赋值运算符 3. 析构函数 1. 拷贝构造函数/合成拷贝构造函数(co ...

  2. C++ 拷贝构造函数与赋值构造函数调用时机初步01

    #include <iostream> #include <string> using namespace std; class Person { public:char *m ...

  3. python定义数组并赋值_python中的数组赋值与拷贝的区别详解

    具体的注解我已经写在了程序里面:通俗的解释了python里面的浅拷贝与深拷贝的不同,请看程序. # -*- coding: utf-8 -*- import numpy as np import co ...

  4. 刷题记录8---验证二叉搜索树+二叉树的层序遍历+从前序与中序遍历序列构造二叉树+二叉树展开为链表+二叉树的最近公共祖先

    前言 所有题目均来自力扣题库中的hot 100,之所以要记录在这里,只是方便后续复习 98.验证二叉搜索树 题目: 给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树. 有效 二叉搜 ...

  5. 【LeetCode系列】从中序与后序遍历序列构造二叉树 从前序与中序遍历序列构造二叉树...

    关注上方"深度学习技术前沿",选择"星标公众号", 资源干货,第一时间送达! 105. 从前序与中序遍历序列构造二叉树 根据一棵树的前序遍历与中序遍历构造二叉树 ...

  6. 105从前序与中序遍历序列构造二叉树 106 从中序与后序遍历序列构造二叉树 (递归 + 哈希)

    引言 这两道题主要是考察二叉树遍历的掌握,即由前序和中序推出原二叉树,由后序和中序推出原二叉树,这里先来说一下推导过程: 前序和中序 知道前序遍历和中序遍历,如何推原二叉树?(直接是结论,可以自行推导 ...

  7. 从前中后序遍历构造二叉树,三题无脑秒杀

    如果只是前中后序遍历的其中一种,是不可能唯一确定一个二叉树的,必须是其中两个的结合,由此便产生了三道题目,在这里可以全部秒杀. 需要记住的要点是: 前序(根左右)--第一个节点一定是根节点: 中序(左 ...

  8. 【C++深度剖析教程1】C++中的经典问题解析-c++中的对象的构造顺序与析构顺序

    c++中的对象的构造顺序与析构顺序 问题一 当程序中存在多个对象时,如何确定这些对象的析构顺序? 一.单个函数创建时构造函数的调用顺序 1.调用父类的构造过程 2.调用成员变量的构造函数(调用顺序与声 ...

  9. [Leedcode][JAVA][第105题][从前序与中序遍历序列构造二叉树][栈][递归][二叉树]

    [问题描述][中等] 根据一棵树的前序遍历与中序遍历构造二叉树.注意: 你可以假设树中没有重复的元素.例如,给出前序遍历 preorder = [3,9,20,15,7] 中序遍历 inorder = ...

  10. 二叉树 中序遍历 python_LeetCode 105 树 从前序与中序遍历序列构造二叉树(Medium)

    17(105) 从前序与中序遍历序列构造二叉树(Medium) 描述 根据一棵树的前序遍历与中序遍历构造二叉树. 注意: 你可以假设树中没有重复的元素. 示例 例如,给出前序遍历 preorder = ...

最新文章

  1. 扁平化职能管理三部曲
  2. 专业的java培训机构是否靠谱,对比一下就知道了!
  3. Quora Question Pairs 项目参考资料
  4. 机器学习 python_送书 | 深入浅出Python机器学习
  5. 运动目标检测、阴影检测及目标跟踪中用得到的标准测试视频下载
  6. ROC 曲线和 AUC 值
  7. 9个元素换6次达到排序序列_(算法四)高级排序(快速排序)
  8. 外设驱动库开发笔记29:DS17887实时时钟驱动
  9. python的精髓_教你玩转Python!一文总结Python入门到精髓的窍门
  10. Asp.net Mvc使用PagedList分页
  11. azure 入门_Azure Cosmos DB中的子文档入门
  12. PAIP.利用SyncML协议来同步备份手机短信联系人.txt
  13. android获取电话通话记录,Android获取手机通话记录
  14. 【BZOJ】2286: [Sdoi2011消耗战【虚树DP】
  15. 苹果笔记本没有计算机管理员,Mac管理员账户丢失怎么办
  16. Python打印简单杨辉三角形
  17. java itext pdf 添加页码
  18. java计算机毕业设计ssm社区团购系统13kbd(附源码、数据库)
  19. 大数据学习路线图(转载)
  20. owlBus 的uwp版本上架了

热门文章

  1. x86 Kylin V10系统安装kvm并创建虚拟机
  2. c语言k1什么意思啊,一张图告诉你斐讯路由器K1S、K2,K2C的区别-路由器交流
  3. uefi装完系统后无法引导_不重装系统修改引导方式为UEFI模式
  4. matlab 无穷符号,如何用matlab进行级数或数列的符号求和?matlab符号求和指令分享...
  5. 2021全球程序员收入报告出炉,字节高级码农年薪274万元排第5!
  6. 工作三年程序员收入到底多高?透露收入:网友:哇,真的好高呀!
  7. 微信小程序生命周期和路由传参详解
  8. redis 中setex、setnx、set、getset 命令的区别与使用
  9. 放大电路中的反馈-反馈的基本概念及判断方法
  10. 词根词缀|ori/orn/ortho/pact/pan及词源O的故事