zoukankan      html  css  js  c++  java
  • C++之拷贝构造函数

    为什么要引入拷贝构造函数?(提出问题)

           作用:创建一个对象的同时,使用一个已经存在的对象给另一个对象赋值

           做比较:拷贝构造函数:对象被创建 +  用一个已经存在的对象 进行初始化

                           拷贝赋值函数:对象已经存在不用创建 + 用一个已经存在的对象进行初始化(区分开初始化操作和赋值)

           举例:string a("hello");//调用构造函数

                       string b("would");//调用构造函数

                       string c=a;//调用拷贝构造函数--风格差,应使用string c(a)

                       c=b;//调用拷贝赋值函数

    什么时候使用拷贝构造函数?(系统自己调用)

           在创建新对象的时候,希望将一个已经存在的对象拷贝给这个新对象,这时系统会自动调用拷贝构造函数

           总结:1、拷贝构造函数的参数必须是引用,否则出错。

                       2、执行的语句类似 Coord p=p1; 则会调用拷贝构造函数                

           有三种情况:

            1)创建一个新类 +  并使用类的一个对象初始化该类的另一个对象

                   Coord p2(p1);//用对象p1初始化对象p2

                   Coord p3=p1;//用对象p1初始化对象p1

            2)函数的形参是类的对象 +  参数使用值传递(参数为引用的时候不调用拷贝构造函数),传参时,会调用拷贝构造函数

     

    fun1(Coord p)
    {
        函数体
    }
    调用语句:
    Coord p1;
    fun1(p1);
    //分析:调用拷贝构造函数 Coord p=p1;
    
    fun1(Coord& p)
    {
        函数体
    }
    调用语句:
    Coord p1;
    fun1(p1); 

    //分析:参数表中使用了引用,没有调用拷贝构造函数啊,执行 Coord& p=p1;

            3)函数的返回值是对象,函数调用完毕,返回调用者时,会调用拷贝构造函数

    Coord fun1(Coord& fun)
    {
        return fun;
    }
    
    调用语句:
    Coord  c;
    Coord p=fun(c); 

    //分析:return fun调用两次拷贝构造函数; VC测试,但是VS2005只调用一次,应该是进行了优化

    Coord& fun1(Coord& fun1)
    {  
        return fun1;
    }
    
    调用语句:
    Coord  c;
    Coord p=fun1(c); 

    // 分析:Coord p=fun1(c)调用一次拷贝构造函数,因为最后使用返回函数引用,return时没有借助临时变量,直接是 Coord p=fun1;  出现这种现象的原因:

    1、在使用return返回一个对象时,系统是先申请一个临时对象temp,执行Coord temp=fun1;(调用一次拷贝构造函数)

          之后在执行Coord p=temp;(第二次调用)

    2、在使用返回函数引用时,系统不会申请临时对象,只是直接把fun1拷贝给p

           即直接执行Coord p=fun1,而没有引入temp,故少用一次拷贝构造函数

          注意:这时要注意一个常出现的错误,返回的值不能是一个临时变量,常常的解决办法是函数参数使用引用,之后在使用return返回即可

    怎么使用拷贝构造函数?

             语法:函数名与类名相同,参数为本对象的引用,无返回类型,只有一个

                        类名::类名(类名& 对象名)

                        {拷贝成员}

             代码:

     

    class Point
    {
    public:
        Point(int xx=0,int yy=0){X=xx; Y=yy;}
        Point(Point&  p);
    private:
        int  X,Y;
    };
    Point::Point (Point& p)
    {
        X=p.X; //参数p可以直接引用私有变量
        Y=p.Y;
    }

     

    注意:参数必须为本对象的引用 + 函数体内参数可以直接引用私有变量(老忘)

     

    常见问题:

     

           1、为什么拷贝函数的参数必须是引用?(拷贝构造函数的参数必须是对象的引用)

     

                  简单点说,为了避免递归。

     

                  具体来说,引用传递的时候不需要调用拷贝构造函数 而 值传递需要调用拷贝构造函数

     

                  所以,在进入拷贝构造函数时,需要把对象传进来,这时使用值传递还要再调一次拷贝构造函数.....这时要无限传递下去

     

           2、浅拷贝与深拷贝

     

                 出现这个问题的原因:构造函数中需要为指针申请空间

     

                 深拷贝:在拷贝构造函数中,为指针显式的申请空间

     

                 浅拷贝:在拷贝构造函数中,仅仅使用成员间的对应复制,两个对象的指针的都指向同一个空间,一个指针指向的空间被释放,再用另一个指针去访问被释放掉的空间,将会导致程序崩溃。

     

                 解决方法:如果构造函数需要为类显示申请空间(含指针,使用new),则要使用显式的拷贝构造函数,如果类中成员都是非指针,则可以使用系统默认的拷贝构造函数。

    浅拷贝代码

      

    #include <iostream>
    #include <string>
    using namespace std;
    class Point
    {
    private:
        char * name;
    public:
        Point(char * className)
        {
            name = new char[strlen(className)+1];
            strcpy(name, className);
        }
         Point(Point& p)//浅拷贝,或者不写
         {
             name = p.name;//(系统默认拷贝函数执行的代码)
         }
        ~Point()
        {
            cout<<name<<endl;//测试关键语句
            delete []name;
        }
    };
    
    int main()
    {
        Point a("123");
        Point b=a;
        return 0;
    }

    深拷贝:

    #include <iostream>
    #include <string>
    using namespace std;
    class Point
    {
    private:
        char * name;
    public:
        Point(char * className)
        {
            name = new char[strlen(className)+1];
            strcpy(name, className);
        }
        Point(Point& p)//深拷贝
        {
            name = new char[strlen(p.name)+1];
            strcpy(name,p.name);
        }
        ~Point()
        {
            cout<<name<<endl;
            delete []name;
        }
    };
    
    int main()
    {
        Point a("123");
        Point b=a;
        return 0;
    }

     

     

     

     

  • 相关阅读:
    236. 二叉树的最近公共祖先
    230. 二叉搜索树中第K小的元素
    221. 最大正方形
    软件构建模式之MVC框架初窥
    九度OnlineJudge之1020:最小长方形
    九度OnlineJudge之1018:统计同成绩学生人数
    九度OnlineJudge之1017:还是畅通工程
    向Python女神推荐这些年我追过的经典书籍
    最实用的10个重构小技巧排行榜,您都用过哪些呢?
    九度OnlineJudge之1014:排名
  • 原文地址:https://www.cnblogs.com/codergeek/p/3354634.html
Copyright © 2011-2022 走看看