原文地址:https://blog.csdn.net/shine_journey/article/details/53081523

1、在C++编码过程中,类的创建十分频繁。

简单的功能,当然不用考虑太多,但是从进一步深刻理解C++的内涵,类的结构和用法,编写更好的代码的角度去考虑,我们就需要用到标题所提到的这些内容。

2、先上代码

  1. // testSingleMode.cpp : 定义控制台应用程序的入口点。
  2. //
  3. #include "stdafx.h"
  4. #include <iostream>
  5. using namespace std;
  6. class Complex
  7. {
  8. private:
  9. double m_real;
  10. double m_imag;
  11. public:
  12. Complex(void){
  13. m_real = 0.0;
  14. m_imag = 0.0;
  15. }
  16. Complex(double real, double imag){
  17. m_real = real;
  18. m_imag = imag;
  19. }
  20. Complex(const Complex & c){ //这里就是最经典的拷贝构造函数了
  21. m_real = c.m_real;
  22. m_imag = c.m_imag;
  23. }
  24. Complex &operator = (const Complex &rhs){   //这里就是最经典的operator=操作符重载了
  25. if (this == &rhs){
  26. return *this;
  27. }
  28. this->m_real = rhs.m_real;
  29. this->m_imag = rhs.m_imag;
  30. return *this;
  31. }
  32. explicit Complex::Complex(double r){    //explicit的用法,只适用于1个参数的情况
  33. m_real = r;
  34. m_imag = 0.0;
  35. }
  36. };
  37. int main()
  38. {
  39. Complex c1, c2; //调用 第15行 默认无参数的构造函数
  40. Complex c3(1.0, 2.5);   //调用 第20行 具有2个形参的构造函数
  41. //Complex c3 = Complex(1.0, 2.5);   //和上一行是一个意思,所以这个注释了
  42. c1 = c3;    //调用 第30行 重载operator=运算符
  43. c2 = c3;    //调用 第30行 重载operator=运算符
  44. //c2 = 5.2; //隐式转换,需要去掉41行的explicit关键字,才可编译通过
  45. Complex c5(c2);     //调用 第25行 拷贝构造函数
  46. Complex c4 = c2;    //调用 第25行 拷贝构造函数
  47. getchar();
  48. return 0;
  49. }

【注1】explicit 只适用于构造函数只含有1个参数的情况,加上这个关键字,意味着不支持构造函数隐式转换,可以避免一些误解。如果去掉这个关键字,那么代码里面的:c2 = 5.2 ; 就是可以执行的了。

【注2】为什么函数中可以直接访问对象c的私有成员?
答:(网上)因为拷贝构造函数是放在本身这个类里的,而类中的函数可以访问这个类的对象的所有成员,当然包括私有成员了。

3、上面代码的注释,已经是非常的清楚了

自定义拷贝构造函数是一种良好的编程风格,它可以阻止编译器形成默认的拷贝构造函数,防止出错。

浅拷贝:如果自己不写拷贝构造函数,系统会默认生成一个,而系统的拷贝构造函数是浅拷贝。

深拷贝:自己写一个拷贝构造函数,系统就不会产生了默认的构造函数了(来自网上说法)。自己写的这个拷贝构造函数,当然会有开辟空间的动作,所以是深拷贝。也就是说,如果生成类的实例的时候,调用了自己写的拷贝构造函数,那么在内存空间上,必然是会开辟新的空间,而不用担心只是一个指针。

在某些状况下,类内成员变量需要动态开辟堆内存,如果实行浅拷贝,也就是把对象里的值完全复制给另一个对象,如A=B。这时,如果B中有一个成员变量指针已经申请了内存,那A中的那个成员变量也指向同一块内存。这就出现了问题:当B把内存释放了(如:析构),这时A内的指针就是野指针了,出现运行错误。

4、总结

(1)深拷贝:如果一个类拥有资源,当这个类的对象发生复制过程的时候,资源重新分配,这个过程就是深拷贝。反之,没有重新分配资源,就是浅拷贝。

(2)什么时候用到拷贝构造函数

  a.一个对象以值传递的方式传入函数体; 
  b.一个对象以值传递的方式从函数返回;
  c.一个对象需要通过另外一个对象进行初始化。

(4)代码例子

  1. #include "stdafx.h"
  2. #include <iostream>
  3. #include <string.h>
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. using namespace std;
  7. class Person
  8. {
  9. public:
  10. // 构造函数
  11. Person(char * pN)
  12. {
  13. cout << "一般构造函数被调用 !\n";
  14. m_pName = new char[strlen(pN) + 1];
  15. //在堆中开辟一个内存块存放pN所指的字符串
  16. if (m_pName != NULL)
  17. {
  18. //如果m_pName不是空指针,则把形参指针pN所指的字符串复制给它
  19. strcpy_s(m_pName, strlen(pN) + 1, pN);
  20. }
  21. }
  22. // 下面自己设计复制构造函数,实现“深拷贝”,即不让指针指向同一地址,而是重新申请一块内存给新的对象的指针数据成员
  23. Person(Person & chs)
  24. {
  25. cout << "拷贝构造函数被调用 !\n";
  26. // 用运算符new为新对象的指针数据成员分配空间
  27. m_pName = new char[strlen(chs.m_pName) + 1];
  28. if (m_pName)
  29. {
  30. // 复制内容
  31. strcpy_s(m_pName, strlen(chs.m_pName) + 1, chs.m_pName);
  32. }
  33. // 则新创建的对象的m_pName与原对象chs的m_pName不再指向同一地址了
  34. }
  35. //// 系统创建的默认复制构造函数,只做位模式拷贝
  36. //Person(Person & p)
  37. //{
  38. //  //使两个字符串指针指向同一地址位置
  39. //  m_pName = p.m_pName;
  40. //}
  41. ~Person()
  42. {
  43. delete m_pName;
  44. }
  45. void getName(){
  46. cout << m_pName << endl;
  47. }
  48. private:
  49. char * m_pName;
  50. };
  51. void main()
  52. {
  53. Person man("lujun");
  54. man.getName();
  55. Person woman(man);
  56. woman.getName();
  57. getchar();
  58. }

程序运行环境: VS2013

输出结果:

C++的拷贝构造函数、operator=运算符重载,深拷贝和浅拷贝、explicit关键字的更多相关文章

  1. C++的转换构造函数、拷贝构造函数、赋值运算符重载

    1 转换构造函数     C++的转换构造函数是只有一个参数的构造函数.当程序试图将一个其他类型的对象或基本类型值赋给该类的一个待初始化对象时(如Person p="Dean";) ...

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

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

  3. C++有关拷贝构造函数(默认/浅/深拷贝构造函数)

    拷贝结构函数顾名思义就是复制对象. 先讲一下默认拷贝函数: 默认拷贝就是直接赋值,让程序调用默认拷贝结构函数. Student p1; Student p2 = p1//或者Student p2(p1 ...

  4. C++“拷贝构造函数”和“等号重载”有什么区别?

    CTypeA(const CTypeB& b)CTypeA& operator=(const CTypeB& b)一直没弄懂这两个有什么区别.只知道,重载了=号,下面复制的时候 ...

  5. c++ 拷贝构造函数(重点在内含指针的浅拷贝和深拷贝)

    今天同事问了一个关于拷贝构造函数的问题,类中包含指针的情况,今天就来说说c++的拷贝构造函数. c++的拷贝构造函数是构造函数的一种,是对类对象的初始化,拷贝构造函数只有一个参数就是本类的引用. 注意 ...

  6. Swift语言精要 - Operator(运算符重载)

    运算符重载 Swift的这一语言特性或许应该启发于C++ class Vector2D { var x : Float = 0.0 var y : Float = 0.0 init (x : Floa ...

  7. C++基础-4-封装(构造函数与析构函数,深拷贝与浅拷贝,静态成员,this,友元,const修饰成员函数)

    4. 封装 4.1.1 封装的意义 1 #include<iostream> 2 #include<string> 3 using namespace std; 4 5 con ...

  8. 【转】 c++拷贝构造函数(深拷贝,浅拷贝)详解

     c++拷贝构造函数(深拷贝,浅拷贝)详解 2013-11-05 20:30:29 分类: C/C++ 原文地址:http://blog.chinaunix.net/uid-28977986-id-3 ...

  9. c++拷贝构造函数(深拷贝,浅拷贝)详解

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

随机推荐

  1. Caffe框架,图像数据转换成LMDB数据格式

    小码农最近在研究深度学习,对所学知识做点记录,以供以后翻阅.在Caffe框架中,数据的格式都是LMDB的,如何将图像数据转换成这个格式呢? 首先,将图像数据和标签生成txt文档,执行一下代码: fin ...

  2. 11.4、Libgdx的音频之录制PCM音效

    (官网:www.libgdx.cn) 可以通过AudioRecorder接口访问PCM数据.通过如下方式创建一个接口实例: AudioRecorder recorder = Gdx.audio.new ...

  3. Socket编程实践(7) --Socket-Class封装(改进版v2)

    本篇博客定义一套用于TCP通信比较实用/好用Socket类库(运用C++封装的思想,将socket API尽量封装的好用与实用), 从开发出Socket库的第一个版本以来, 作者不知道做了多少改进,  ...

  4. (NO.00003)iOS游戏简单的机器人投射游戏成形记(一)

    这是一个简单的机器人投射游戏,主要来熟悉物理引擎的一些东西.你可以把它认为是机器人投篮;尽管投出的是抛物线,但不是篮球而是子弹,速度也较快. 游戏玩法是玩家选择机器人,移动机器人手臂瞄准篮框,然后发射 ...

  5. 实例说明Java中的null

    翻译人员: 铁锚 翻译时间: 2013年11月11日 原文链接: What exactly is null in Java? 让我们先来看下面的语句: String x = null; 1. 这个语句 ...

  6. ceres-solver库使用示例

    上一篇博客大致说明了下ceres-solver库的编译,然后形成了一个二次开发的库,下面就是用这个二次开发库来写一个简单(其实不太简单)的DEMO来演示ceres-solver库的强大.我们以求解一个 ...

  7. Leetcode_141_Linked List Cycle

    本文是在学习中的总结,欢迎转载但请注明出处:http://blog.csdn.net/pistolove/article/details/42833739 Given a linked list, d ...

  8. 【Qt编程】Qt学习之状态栏

    QStatusBar类提供一个水平条来显示状态信息.所谓状态信息,拿个简单的例子来说,当你在word中编辑时,左下角就会出现页面.字数等等信息.状态信息可以分为三类:临时信息,如一般的提示信息:正常信 ...

  9. UE4 Hello World 创建第一个UE4工程

    首先先熟悉几个UE4常用的类 AGameMode(控制整个项目的逻辑) The GameMode defines the game being played. It governs thegame r ...

  10. Java深拷贝浅拷贝

    首先,Java中常用的拷贝操作有三个,operator = .拷贝构造函数 和 clone()方法.由于Java不支持运算符重载,我们无法在自己的自定义类型中定义operator=.拷贝构造函数大家应 ...