【C++】String拷贝(包含深拷贝浅拷贝)以及拷贝构造函数中几种调用的情况

之前我们已经讲过了类和对象,但是其中我们没有仔细的分析构造函数以及拷贝构造函数。
现在我们仔细的来分析一下这两类函数。

**构造函数**

    在写构造函数时,必要情况下我们要给一些值进行初始化,不然在运行时可能会出现无法预知的错误

  初始化也分为两种:
     (1)第一种是缺省的,也就是在定义构造函数时,我们就给其对象赋予初值,当在使用构造函数时,如果没有给其赋值,那么系统就会使用我们默认给的值
    例如:
    #include<iostream>
    using namespace std;
    class Time
    {
    public:
    //需要注意,构造函数的名字与类名一定要一致
      Time(int hour = 0,int minute = 0,int second = 0)
      {
        _hour = hour;
        _minute = minute;
        _second = second;
      }
    private :
     int _hour;
     int _minute;
     int _second;
    };
    int main()
    {
        Time time1();//使用缺省值
        Time time2(2017,10,22);//重新赋值
        cout<<time1<<endl;
        cout<<time2<<endl;
    }


(2)第二种就是用初始化列表进行初始化,以上面的例子为继:
格式为:
Time(int hour = 0 , int minute = 0 ,int second  = 0 )
:_hour(hour),_minute(minute),_second(second)
    {}
这种情况就显得很简单了,初始化时都会进行。

接下来就是拷贝构造函数了,拷贝构造函数也是构造函数的一种,但是它提供参数,但没有返回值。

Time(const Time& t)
{
_hour = t._hour;
_minute = t._minute;
_second = t._second;

}

拷贝时存在深拷贝和浅拷贝

    //拷贝构造浅拷贝
    String(String& s) :_str(NULL)
    {
        _str = s._str;
    }
    //深拷贝
    String(String& s)
    {
        String tmp(s._str);
        swap(_str, tmp._str);
    }

为什么会存在深拷贝和浅拷贝??深拷贝与浅拷贝有哪些区别?
假如我们在学校里都不爱写作业,那么我们就会去抄作业,然后我们选了一个学习中等的同学的作业去抄,抄完了之后,那个同学发现他写错了,那他就会改正,那借他作业抄的同学也要跟着改正,这就相当于是浅拷贝。 如上,_str 和 s._str 指向的是同一块空间,在我们修改或更新 s._str 的时候,原本写好的 _str 就会跟着改变,这就是浅拷贝。而深拷贝就相当于是 A 把作业借给了 B,B 作业写完了之后借给了C,A 修改作业但是 C 不知道,C 就不会修改他的作业,除非有人告诉他。上面的例子就是:s._str 拷贝给了 tmp ,然后 tmp 把自己的值给了 _str ,这时 tmp 出了这个作用域就已经不存在了, _str 和 s._str 就互相不干扰了。实际上通俗的讲,就是 s._str 和 tmp 各指向了一块空间,地址不同,但是内容却相同,然后 _str 也指向了 tmp 的那块空间,当tmp不存在的时候,那块地址还有 _str 指向,所以不会销毁 。但是 s._str 和 _str 又没有指向同一块空间,所以 s. _str 改变不会改变_str的值。

下面几张图就是我们在深浅拷贝时观察到的,就会很容易的区分出深浅拷贝

浅拷贝前后的地址:

这里写图片描述
这里写图片描述

深拷贝前后的地址:

这里写图片描述

这里写图片描述

拷贝构造里还有几种情况值得我们注意:

(1)用类的一个对象去初始化另一个对象时需要调用拷贝构造函数
(2)当函数的返回值是类的对象或引用会调用拷贝构造函数
(3)当函数的形参是类的对象时,使用值传递的方法传递时会调用拷贝构造函数,如果是引用则不会调用
代码做证明:

#include<iostream>
using namespace std;
class AA
{
public :
    //构造函数
    AA(int a)
    {
        _a = a;
    }

    int get()
    {
        return _a;
    }
    //情况一 初始化一个对象
    AA(AA& a)
    {
        _a = a._a;
        cout << "该情况调用了拷贝构造函数!" << endl;
    }
    //情况二,返回值是对象类型
    //为什么调用拷贝构造函数,因为函数体内生成的对象aa是临时的,离开这个函数就消失了。
    //则会调用拷贝构造函数复制一份再传回。
    AA get_A()
    {
        AA a(1);
        return a;
    }
    //返回值为引用类型,返回的是别名,则不需要调用
    AA& get_A1()
    {
        AA a(2);
        return a;
    }
    //情况三,对象类型做参数时,值传递
    int get_A2(AA a)
    {
        _a = a._a;
        return _a;
    }
    //引用做参数时,传给的是别名,不需要拷贝
    int get_A3(AA& a)
    {
        _a = a._a;
        return _a;
    }

private:
    int _a;
};

void test()
{
    //第一种情况
    //AA x(3);   //调用构造函数
    //AA y(x);   //调用拷贝构造函数
    /*cout << x.get() << endl;
    cout << y.get() << endl;*/

    第二种情况
    //AA x1(5);
    //x1.get_A();//调用拷贝构造函数
    //x1.get_A1();//不调用拷贝构造函数

    //第三种情况
    AA x2(4);
    int c = x2.get_A2(x2);//调用拷贝构造函数
    int d = x2.get_A3(x2);//不调用拷贝构造函数
}


#include"String.h"
#include<stdlib.h>

int main()
{
    test();
    system("pause");
    return 0;
}

到这里,拷贝构造函数就告一段落,但是学习却没有停止,若有不足,希望大家能够多多指教。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值