zoukankan      html  css  js  c++  java
  • 稍微深入点理解C++复制控制【转】

    通过一个实例稍微深入理解C++复制控制过程,参考资料《C++ primer》,介绍点基本知识:

    1、在C++中类通过特殊的成员函数:复制构造函数、赋值操作符和析构函数来控制复制、赋值和撤销该类的对象时会发生什么。

    2、复制构造函数(copy constructor)是一种特殊的构造函数,具有单个形参,该形参(常用const)是对该类类型的引用;

    • 当定义一个新对象并用一个同类型的对象对它进行初始化时,将显示使用复制构造函数;
    • 当将该类的对象传递给函数或从函数返回该类型的对象时,将隐式使用复制构造函数。

    3、复制构造函数可用于:

    • 根据另一个同类型的对象显示或隐式初始化一个对象;
    • 复制一个对象,将它作为实参传给一个函数;
    • 从函数返回时复制一个对象;
    • 初始化顺序容器中的元素;
    • 根据元素初始化式列表初始化数组元素。

    4、如果我们在类体中没有定义复制构造函数,编译器就会为我们合成一个复制构造函数。与合成的默认构造函数不同,即使我们定义了其他构造函数,也会合成复制构造函数。

        合成复制构造函数的行为:执行逐个成员初始化,将新对象初始化为原对象的副本。

        有些类经常有的数据成员是指针,这时我们必须对复制对象时发生的事情加以控制,否则当复制的对象析构或者删除时,对象中的指针不再指向有效对象,则会出现悬垂指针情况,这时我们必须要定义自己的复制构造函数。

    5、有些类需要完全禁止复制,例如,iostream类就不允许复制,如果不想复制,则应明确禁止,可以将复制构造函数声明为private,并且不定义。

    6、赋值操作符(assignment operator):同复制构造函数一样,如果在类体中没有定义赋值操作符,编译器也会为我们合成一个赋值操作符。它会执行逐个成员复制:右操作数对象的每个成员赋值给左操作数对象的对应成员。

        如:

    复制代码
    Sales_item& Sales_item::operator=(const Sales_item &rhs)
    {
        isbn = rhs.isbn;
        units_sold = rhs.units_sold;
        revenue = rhs.revenue;
        return *this;
    }
    复制代码

    7、析构函数(destructor):是构造函数的互补,当对象超出作用域或动态分配的对象(new、malloc)被删除时,将自动应用析构函数。

    下面通过一个实例详细说明复制构造函数、赋值操作符、析构函数的调用机制,代码中已有详细解释,故在此不再赘述~

    复制代码
     1 /************************************************
     2 *
     3 *     内容摘要:定义Expm1类,该类给出复制控制成员和其他构造函数
     4 *              用不同方式使用Expm1类型的对象:
     5 *              作为非引用形参和引用形参传递,动态分配
     6 *              作为函数返回值,进行赋值操作,作为元素放在vector容器中。
     7 *              研究何时执行哪个构造函数和复制控制成员
     8 *    
    9 * 日 期:2012.8.27 by Jacky Liu 10 * 11 ************************************************/ 12 13 #include <vector> 14 #include <iostream> 15 16 struct Expm1 17 { 18 //默认构造函数 19 Expm1() 20 { 21 std::cout<<"Expm1()"<<std::endl; 22 } 23 24 //复制构造函数 25 Expm1(const Expm1 &) 26 { 27 std::cout<<"Expm1 (const Expm1&)"<<std::endl; 28 } 29 30 //复制操作符 31 Expm1 & operator = (const Expm1 &) 32 { 33 std::cout<<"operator = (const Expm1&)"<<std::endl; 34 return *this; 35 } 36 37 //析构函数 38 ~Expm1() 39 { 40 std::cout<<"~Expm1()"<<std::endl; 41 } 42 }; 43 44 void func1(Expm1 obj) //形参为Expm1对象 45 {} 46 47 void func2(Expm1 & obj) //形参为Expm1对象的引用 48 {} 49 50 Expm1 func3() 51 { 52 Expm1 obj; 53 return obj; //返回Expm1对象 54 } 55 56 int main() 57 { 58 std::cout<<"1-------------------------------------"<<std::endl<<std::endl; 59 60 Expm1 eobj; //调用默认构造函数创建Expm1对象eobj 61 62 std::cout<<"2-------------------------------------"<<std::endl<<std::endl; 63 64 func1(eobj); //调用复制构造函数 65 //将形参Expm1对象创建为实参Expm1对象的副本 66 //函数执行完毕后调用析构函数撤销形参Expm1对象 67 68 std::cout<<"3-------------------------------------"<<std::endl<<std::endl; 69 70 func2(eobj); //形参为Expm1对象的引用,无需调用复制构造函数传递实参 71 72 std::cout<<"4-------------------------------------"<<std::endl<<std::endl; 73 74 eobj = func3(); //调用默认构造函数创建局部Expm1对象 75 //函数返回时调用复制构造函数创建作为返回值副本的Expm1对象 76 //然后调用析构函数撤销局部Expm1对象 77 //然后调用赋值操作符 78 //执行完赋值操作后 79 //调用析构函数撤销作为返回值副本的Expm1对象 80 81 std::cout<<"5-------------------------------------"<<std::endl<<std::endl; 82 83 Expm1 *p = new Expm1; //调用默认构造函数动态创建Expm1对象 84 85 std::vector<Expm1> evec(3); //调用默认构造函数创建一个临时值Expm1对象 86 //调用复制构造函数,将临时值Expm1对象复制到vector容器evec的每个元素 87 //调用析构函数撤销临时值Expm1对象 88 //按以上重复三次 89 90 std::cout<<"6-------------------------------------"<<std::endl<<std::endl; 91 delete p; //调用析构函数撤销动态创建的Expm1对象 92 93 system("pause"); 94 return 0; //eobj及evec生命期结束,自动调用析构函数撤销 95 96 }
    复制代码

    运行结果:仔细观察运行结果的执行情况,可以深入理解C++中的复制控制机制~

  • 相关阅读:
    unexpected inconsistency;run fsck manually esxi断电后虚拟机启动故障
    centos 安装mysql 5.7
    centos 7 卸载mysql
    centos7 在线安装mysql5.6,客户端远程连接mysql
    ubuntu 14.04配置ip和dns
    centos7 上搭建mqtt服务
    windows eclipse IDE打开当前类所在文件路径
    git 在非空文件夹clone新项目
    eclipse中java build path下 allow output folders for source folders 无法勾选,该如何解决 eclipse中java build path下 allow output folders for source folders 无法勾选,
    Eclipse Kepler中配置JadClipse
  • 原文地址:https://www.cnblogs.com/zhanjxcom/p/5565085.html
Copyright © 2011-2022 走看看