C++进阶系列:深拷贝浅拷贝函数与拷贝赋值操作符

类使用构造函数对对象进行初始化外,还有拷贝、赋值、销毁等操作。
如果在类的定义中不自己定义默认拷贝赋值构造函数与析构函数,编译器会自动创建合成函数,在初始化时使用类内初始值或默认值初始化成员。
编译器自动生成提供的默认拷贝构造函数是浅拷贝,所谓浅拷贝,则是简单将成员进行赋值操作,通常如果类成员只有简单数据成员时,浅拷贝不会出现任何问题。但是,如果成员中存在指针或引用时,执行浅拷贝则只是将指针或引用赋值,而具体指向的是同一内存空间,在修改值时会出现意想不到的问题,而且,最重要是在析构时同一内存单元重复释放两次。而深拷贝的构造函数不能自动生成需自己实现。

值得注意的是:

Rect<int> rect2(0, 0);
rect2 = rect;
//此时是先调用构造函数,再调用赋值构造函数
//如果没有自定义赋值操作,则默认浅拷贝则会出现问题

Rect<int> rect3 = rect; 
//这种情况下,直接调用拷贝构造函数
//如果没有自定义拷贝构造函数,即使自定义了=操作
//也会默认生成浅拷贝构造函数,出现问题

另一点值得注意的是:
当类作为返回值时,会调用拷贝构造函数,将结果return给一个临时对象。
不过,在某些情况下,编译器会自动进行返回值优化,避免过多重复拷贝。返回值优化(return value optimization,RVO),它是一种编译器优化操作,可以消除返回非引用对象在调用处创建的临时对象。

Rect<int> rect4 = doNothing(rect);//调用拷贝构造函数

Rect<int> rect5(0, 0);//先构造,调用带参数构造函数
rect5 = doNothing(rect);//调用拷贝构造函数,再调用赋值函数

完整代码如下:

//定义一个矩形类模板
//模板中含有计算矩形面积和周长的成员函数
//数据成员为矩形的长和宽。

#include <iostream>

using namespace std;

template <typename T>
class Rect
{
public:
    Rect(T a, T b) :m_lenth(a), m_width(b)
    {
        scale = new int;
    }
    Rect(const Rect<T> &rect)
    {
        cout << "拷贝" << endl;
        scale = new int;
        *scale = rect.getScale();
        m_lenth = rect.getLength();
        m_width = rect.getWidth();
    }
    ~Rect()
    {
        delete scale;
    }
    Rect<T>& operator=(const Rect<T> &rect)
    {
        cout << "赋值" << endl;
        scale = new int;
        *scale = rect.getScale();
        m_lenth = rect.getLength();
        m_width = rect.getWidth();
        return *this;
    }
    T calcArea()
    {
        return m_lenth * m_width * *scale;
    }
    T calePerimeter()
    {
        return 2 * (m_lenth + m_width) * *scale;
    }
    void setScale(int _scale)
    {
        *scale = _scale;
    }
    int getScale() const 
    {
        return *scale;
    }

    T getLength() const
    {
        return m_lenth;
    }
    T getWidth() const 
    {
        return m_width;
    }

    void show_info()
    {
        cout << calcArea() << endl;
        cout << calePerimeter() << endl;
    }

private:
    T m_lenth;
    T m_width;
    int *scale;
};

template <typename T>
Rect<T> doNothing(const Rect<T> &rect)
{
    return rect;
}
int main(void)
{
    Rect<int> rect(3, 5);
    rect.setScale(1);

    Rect<int> rect2(0, 0);//先构造
    rect2 = rect;         //再赋值,调用赋值函数

    Rect<int> rect3 = rect; //调用拷贝构造函数

    rect.setScale(2);

    Rect<int> rect4 = doNothing(rect);//调用拷贝构造函数

    Rect<int> rect5(0, 0);//先构造,调用带参数构造函数
    rect5 = doNothing(rect);//调用拷贝构造函数,再调用赋值函数

    rect.show_info();
    rect2.show_info();
    rect3.show_info();

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值