拷贝构造函数、赋值函数浅析

注:以下为阅读网络上以及书上的相关内容后,自己总结的结果。因参考资料众多,无法附上链接,在此抱歉。

一个类A,如果什么都不编写,c++编译器将自动为A产生四个默认的函数(实际上还有两个,在此不列出),即:

函数名称
A(void)1、默认无参数构造函数
A(const A &a)2、默认拷贝构造函数
~A(void);3、默认的析构函数
A & operator = (const A &a);4、默认的赋值函数


对于构造函数和析构函数我们都了解。那么拷贝构造函数赋值函数是什么呢?

一、基本概念

1、拷贝构造函数:(也叫复制构造函数)

拷贝构造函数是C++独有的,它是一种特殊的构造函数,简单地说,是用来初始化另一个类对象的函数。

当没有重载拷贝构造函数时,即没有在类里面重写拷贝构造函数时,通过默认拷贝构造函数来创建一个对象:

class A {
public: 
    A(A& x)        // 第一种形式
    A(const A& x)  // 第二种形式
    A(A& x, int a = 0, int b = 1…) // 第三种形式
};
A a;
A b(a);   // 这里b对象还没有存在,是用 a 对象来构造和初始化 b 的!
          // 第一种写法
A b=a;    // 第二种写法
2、赋值函数:

当一个类的对象向该类的另一个对象赋值时,就会用到该类的赋值函数。

当没有重载赋值函数时,通过默认赋值函数来进行赋值操作:
(赋值函数本质是赋值操作符,重载赋值函数即重写赋值操作符

class A {
    //……
};
A a;
A b;    // 这里b对象是已经存在的,是用 a 对象来赋值给 b 的!
b=a; 

二、为何要自己重写

既然系统能自动生成这些函数,为什么还需要自定义?

最重要的原因是:默认的拷贝构造函数 和 默认的赋值函数 均采用 位拷贝 而非 值拷贝。

位拷贝 拷贝的是地址,而 值拷贝 拷贝的是内容
位拷贝 == 浅拷贝 == 按位拷贝
值拷贝==深拷贝 == 按值拷贝

浅拷贝会发生的问题:

  • a原来的内存区域未释放,造成内存泄露。
  • a和b指向同一块区域,任何一方改变,会影响到另一方。
  • 当对象释放时,b会释放掉两次。

因此:当类中还有指针变量时,拷贝构造函数 和 赋值函数 就隐含了错误。此时需要自己定义。

具体解释网上有一位解释的非常好,找时间把地址贴过来。

不理解也没关系,只要记住一件事就好:必须要重写!

如果不想写拷贝构造函数和赋值函数,又不允许别人使用编译器生成的默认的函数,最简单的办法是将拷贝构造函数和赋值函数声明为私有函数

class A
{
    private:
    A(const A& a);           // 私有拷贝构造函数
    A& operate=(const A& a); // 私有赋值函数
}

三、什么情况下使用

什么情况用到拷贝构造函数:
1)一个对象以值传递的方式传入函数体
2)一个对象以值传递的方式从函数返回
3)一个对象需要通过另一个对象进行初始化

class A {
public: 
    A(A& x)        // 第一种形式

};
int Fun1(A x)
{
   return x.a + x.b;
}

A Fun2(int a, int b)
{
    A a(a, b);
    return a;                                      
}
A c(10, 10);
A d(c);              // 情况1) -> 调用拷贝构造函数
int e = Fun1(c);     // 情况2) -> 调用拷贝构造函数
A f = Fun2(11, 11);  // 情况3) -> 调用拷贝构造函数


P.S.

赋值函数需要处理自我赋值的问题,因为自我赋值会出现指针指向一个已经释放的内存。(详见最后一个链接的文章)

例子:

String::String(const String &other)
{
    cout << "自定义拷贝构造函数" << endl;
    int length = strlen(other.m_data);
    m_data = new char[length + 1];
    strcpy(m_data, other.m_data);
}

String & String::operator=(const String &other)
{
    cout << "自定义赋值函数" << endl; 

    if (this == &other) //※
    {
        return *this;
    }
    else
    {
        delete [] m_data;
        int length = strlen(other.m_data);
        m_data = new char[length + 1];
        strcpy(m_data, other.m_data);
        return *this;
    }
}

四、文章推荐

几篇我认为对我帮助很大的好文章:

C++类中拷贝构造函数详解

C++中构造函数,拷贝构造函数和赋值函数的区别和实现

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

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

C++赋值函数详解

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值