1. 何时调用复制构造函数
  复制构造函数用于将一个对象复制到新创建的对象中。也就是说,它用于初始化过程中,而不是常规的赋值过程中。类的复制构造函数原型通常如下:
  class_name(const class_name&);
  它接受一个指向类对象的常量引用作为参数。例如,String类的复制构造函数的原型如下:
  String(const String&);
  新建一个对象并将其初始化为同类现有对象时,复制构造函数都将被调用。这在很多情况下都可能发生,最常见的情况是将新对象显示地初始化为现有的对象。例如,假设motto是一个String对象,则下面4种声明都将调用复制构造函数:
  String ditto(motto);
  String metoo = motto;
  String also = String(motto);
  String *pString = new String(motto);
  其中中间的2种声明可能会使用复制构造函数直接创建metto和also,也可能会使用复制构造函数生成一个临时对象,然后将临时对象的内容赋给 metoo和also,这取决于具体的实现。最后一种声明使用motto初始化一个匿名对象,并将新对象的地址赋给pString指针。
2. 何时调用赋值构造函数
  赋值构造函数是通过重载赋值操作符实现的,这种操作符的原型如下:
  Class_name& Class_name::operator=(const Class_name&);
  它接受并返回一个指向类对象的引用。例如,String 类的赋值操作符的原型如下:
  String& String::operator=(const String&);
  将已有的对象赋给另一个对象时,将使用重载的赋值操作符:
  String headline1("test");
  String knot;
  knot = headline1;
  初始化对象时,并不一定会使用赋值操作符:
  String metoo = knot;
  这里,metoo是一个新创建的对象,被初始化为knot的值,考试,大提示使用复制构造函数。不过,正如前面指出的,实现时也可能分两步来处理这条语句:使用复制构造函数创建一个临时对象,然后通过赋值将临时对象的值复制到新对象中。这就是说,初始化总是会调用复制构造函数,而使用=操作符时也可能调用赋值操作符
  实例代码如下:
  #include <iostream>
  using namespace std;
  class Test
  {
  public:
  Test();
  ~Test();
  Test(const Test& t);
  Test& operator=(const Test& t);
  private:
  int t1;
  };
  Test::Test()
  {
  cout<<"调用构造函数"<<endl;
  }
  Test::~Test()
  {
  cout<<"调用析构函数"<<endl;
  }
  Test::Test(const Test& t)
  {
  cout<<"调用复制构造函数"<<endl;
  }
  Test& Test::operator =(const Test& t)
  {
  cout<<"调用赋值构造函数"<<endl;
  t1 = t.t1;
  return *this;
  }
  void main()
  {
  Test t1;
  Test t2 = t1;
  Test t3;
  t3 = t1;
  }
  输出如下:
  调用构造函数
  调用复制构造函数
  调用构造函数
  调用赋值构造函数
  调用析构函数
  调用析构函数
  调用析构函数

同样是利用现有对象的值,生成/更新另一个对象的值。区别在于:复制构造函数是去完成对未初始化的存储区的初始化,而赋值操作符则是处理一个已经存在的对象。对一个对象赋值,当它一次出现时,它将调用复制构造函数,以后每次出现,都调用赋值操作符。

定义对象a,并用另一个对象b对a进行初始化时,
若没有复制构造函数时,那么编译器会自动生成一个
T b(1);//假设对象b已经初始化
T a(b);//初试化阶段,调用复制构造函数
T c = b;//虽然使用了“=”,但是初试化阶段,仍调用复制构造函数
T c = a; //因为对象c已经定义,所以此处调用赋值操作符重载函数。如果没有编译器会自动生成一个。

3.拷贝构造函数的标准写法如下:

拷贝构造函数必须是引用传递传递地址,不可以值传递,否则会陷入无限循环创建的过程。

class Base
{
public:
  Base(){}
  Base(const Base &b){..}
  //
}

上述写法见得最多,甚至你认为理所当然。
那么如果我们不写成引用传递呢,而是值传递,那么会怎样?

class Base
{
public:
  Base(){}
  Base(const Base b){}
  //
}

编译出错:error C2652: 'Base' : illegal copy constructor: first parameter must not be a 'Base'

事实上,你可以从这个小小的问题认真搞清楚2件事:
1) 拷贝构造函数的作用就是用来复制对象的,在使用这个对象的实例来初始化这个对象的一个新的实例。其实,个人认为不应该叫这些constructor(default constructor, copy constructor....)为构造函数,更佳的名字应该是"初始化函数"(见我的另一片文章).

2) 参数传递过程到底发生了什么?
    将地址传递和值传递统一起来,归根结底还是传递的是"值"(地址也是值,只不过通过它可以找到另一个值)!
i)值传递:
    对于内置数据类型的传递时,直接赋值拷贝给形参(注意形参是函数内局部变量);
    对于类类型的传递时,需要首先调用该类的拷贝构造函数来初始化形参(局部对象);如void foo(class_type obj_local){}, 如果调用foo(obj);  首先class_type obj_local(obj) ,这样就定义了局部变量obj_local供函数内部使用
ii)引用传递:
    无论对内置类型还是类类型,传递引用或指针最终都是传递的地址值!而地址总是指针类型(属于简单类型), 显然参数传递时,按简单类型的赋值拷贝,而不会有拷贝构造函数的调用(对于类类型).

上述1) 2)回答了为什么拷贝构造函数使用值传递会产生无限递归调用...

3). 如果不显式声明拷贝构造函数的时候,编译器也会生成一个默认的拷贝构造函数,而且在一般的情况下运行的也很好。但是在遇到类有指针数据成员时就出现问题了:因为默认的拷贝构造函数是按成员拷贝构造,这导致了两个不同的指针(如ptr1=ptr2)指向了相同的内存。当一个实例销毁时,调用析构函数free(ptr1)释放了这段内存,那么剩下的一个实例的指针ptr2就无效了,在被销毁的时候free(ptr2)就会出现错误了, 这相当于重复释放一块内存两次。这种情况必须显式声明并实现自己的拷贝构造函数,来为新的实例的指针分配新的内存。

上述3)回答了在类中有指针数据成员时,拷贝构造函数使用值传递等于白显式定义了拷贝构造函数,因为默认的拷贝构造函数就是这么干的...

拷贝构造函数和赋值构造函数的区别相关推荐

  1. 不存在从void转换到sqlist的适当构造函数_拷贝构造函数与赋值构造函数

    拷贝构造函数与赋值构造函数 在C++中,如果要创建一个新的类,并用已有的类来给它附初值.就要用到拷贝构造函数,拷贝构造函数又分为两种. 1.合成的拷贝构造函数 在你没有定义自己的拷贝构造函数而又调用了 ...

  2. 对于拷贝构造函数和赋值构造函数的理解

    昨天晚上在看智能指针的时候,我发现自己连一个拷贝构造函数和赋值构造函数都写不出来,自己就尝试写了一个版本,结果发现错误百出,对于拷贝构造函数和赋值构造函数的理解仅仅停留在理论的方面,而不知其中太多的内 ...

  3. 拷贝构造函数和赋值构造函数声明为私有的作用

    转贴地址:http://blog.csdn.net/winer632/archive/2009/01/12/3762292.aspx 每个类只有一个赋值函数. 由于并非所有的对象都会使用拷贝构造函数和 ...

  4. C++ 拷贝构造函数和赋值构造函数

    在C++中复制控制是一个比较重要的话题,主要包括复制构造函数.重载赋值操作符.析构函数这三部分,这三个函数是一致的,如果类需要析构函数,则它也需要复制操作符 和 复制构造函数,这个规则被称为 C++的 ...

  5. C++---拷贝构造函数和赋值构造函数

    摘要:最近看了一道面试题问:C++ 中拷贝赋值函数的形参能否进行值传递?我知道一般来说,拷贝构造函数的形参必须是自身类型的引用(<面向对象程序设计--C++语言描述(第二版)>这本书中有叙 ...

  6. 复制构造函数 与 赋值函数 的区别

    构造函数.析构函数.赋值函数是每个类最基本的的函数.每个类只有一个析构函数和一个赋值函数.但是有很多构造函数(一个为复制构造函数,其他为普通构造函数.对于一个类A,如果不编写上述四个函数,c++编译器 ...

  7. Cpp 对象模型探索 / 拷贝构造函数 和 赋值构造函数 的调用时机

    class A { public:A() {};A(const A& obj) {}A& operator=(const A& obj) { return *this; } } ...

  8. 网易游戏笔试题:编写string类的构造函数、拷贝构造函数、赋值构造函数和析构函数

    题目: class MyString { public: MyString(const char *str);//构造函数 MyString(const MyString& strClass) ...

  9. C++中拷贝构造、赋值构造的区别

    构造函数 是一种特殊的方法 主要用来在创建对象时初始化对象 即为对象成员变量赋初始值.一个类也可以有多个构造函数,用来初始化不同形式的类. 构造函数被调用通常发生在以下三种情况, 第一种情况就是用一个 ...

  10. C++中拷贝构造函数与赋值构造函数详解

    1.  拷贝构造函数 什么时候会调用拷贝构造函数  ?            使用一个已经创建好的对象来初始化一个新的对象. Student mya("zhang3",22);   ...

最新文章

  1. python装饰器执行顺序_python unittest单元测试框架-3用例执行顺序、多级目录、装饰器、fixtures...
  2. Ubuntu终止进程的方法(kill、pkill、killall)
  3. cocos2d-x游戏实例(18)-纵版射击游戏(5)
  4. java金字塔的流程图,R中的金字塔图
  5. Source Generators(源代码生成器)的调试器支持 | Visual Studio 2019(16.10)新功能试用...
  6. 戴尔新版bios设置中文_戴尔电脑装机过程
  7. VBA操作word生成sql语句
  8. JavaScript+ Canvas开发趣味小游戏《贪吃蛇》
  9. getresourceasstream方法_【设计模式】第三篇:一篇搞定工厂模式【简单工厂、工厂方法模式、抽象工厂模式】...
  10. android 6.0适应的机型,提升用户体验 可升Android 6.0机型盘点
  11. 情人节,怎么同时约会女神和女朋友
  12. linux snap文件夹,在Linux下使用Snap安装Rambox的方法
  13. Android 使用Fragment,ViewPagerIndicator 制作csdn app主要框架
  14. 【饭谈】为什么有的技术博文你看不懂?
  15. 我国超级计算机的发展成就,中国最近的科技发展成就
  16. 程序员debug三大定律
  17. wps中制作图表目录
  18. Android学习方向
  19. 安全测试涉及的测试对象有哪些?
  20. 基于机器学习中集成学习的stacking方式进行的金线莲质量鉴别研究(python进行数据处理并完成建模,对品种进行预测)

热门文章

  1. YYYY-mm-dd HH:MM:SS 备忘录
  2. Jmeter参数化HTTP request中Send Files With The Request的文件路径和文件名
  3. 一线架构师实践指南阅读体会_ADMEMS方法体系理解
  4. MySQL不区分大小写(Linux与WINDOWS)
  5. 【ProjectT】Tapestry • Quick Start • Forms
  6. java selector wakeup_Selector
  7. 计算机网络学习方法和书籍推荐
  8. 自定义List接口及相关方法
  9. 七大排序的 java 实现和理解
  10. 和为S的两个数字(python)