深拷贝 右值操作 移动语义

例1

深拷贝 

#include<iostream>

class A
{
    public:
        A():_n(0),_p(NULL){}
        explicit A(int n):_n(n),_p(new int[n]){}
        A(int n,int *p):_n(n),_p(p){}

        //这是拷贝构造 使用const关键字修饰表示不修改引用内容
        A(const A & that);
        //这是操作符重载,也叫赋值构造函数
        //返回A类类型的一个引用,传入的是A类型的一个引用,不修改引用的内容,使用const
        A & operator=(const A & that);

        virtual ~A(){if(_p) delete[] _p,_p=NULL;}
    public:
        //下标操作符重载,表示返回一个int类型的引用,传入的参数时int类型的变量
        int & operator[](int i);
        //下标操作符的另一种形式
        const int & operator[](int i)const;
         void display()
        {
            for(int i=0;i<this->_n;i++)
                std::cout<<this->_p[i]<<" ";
            std::cout<<std::endl;
        }
    private:
        int _n;
        int *_p;
};
//构造函数的实现
A::A(const A & that)
{
    //将传进来的that._n赋值给当前对象的_n数据对象
    this->_n = that._n;
    //然后动态开辟一片存储区域,大小为this->_n
    //然后使用for循环将that._p[i]赋给this->_p[i]
    this->_p = new int[this->_n];
    for(int i=0;i<this->_n;i++)
        this->_p[i] = that._p[i];
    //构造函数没有返回值
}
//=重载函数的实现
A & A::operator=(const A & that)
{
    this->_n = that._n;
    //如果当前指针存在先进行销毁
    if(_p)
        delete[] _p;
    _p = new int[_n];
    for(int i=0;i<_n;i++)
        _p[i] = that._p[i];
    //最后返回一个引用
    return *this;
}
//[]重载函数的实现
int & A::operator[](int i)
{
    return _p[i];
}
const int & A::operator[](int i)const
{
    return _p[i];
}
int main()
{
    A a(4);
    for(int i=0;i<4;i++)
        a[i]=i+1;
    std::cout<<"a.display"<<std::endl;
    a.display();
    
    A b = a;//使用赋值构造函数将a对象的数据对象赋值给b对象
    std::cout<<"b.display"<<std::endl;
    b.display();

    A c(4);
    for(int i=0;i<4;i++)
        c[i]=i+1;
    std::cout<<"c.display"<<std::endl;
    c.display();

    A d(c);//使用拷贝构造函数,将c的数据对象拷贝给d对象
    std::cout<<"d.display"<<std::endl;
    d.display();
    return 0;

}

输出:

a.display
1 2 3 4
b.display
1 2 3 4
c.display
1 2 3 4
d.display
1 2 3 4

例2

使用右值操作实现移动赋值和移动赋值构造函数

#include <iostream>
class A{
    public:
        //构造函数
        A():_n(0),_p(nullptr){}
        //但参数构造函数
        explicit A(int n):_n(n),_p(new int[n]){}
        //双参数构造函数
        A(int n,int *p):_n(n),_p(p){}
        //——————————&&表示右值引用,在函数内部也是按照左值对待——————————//
        A(A && that);//右值引用拷贝构造函数
        A & operator=(A && that);//右值引用”=“重载构造函数,或者叫赋值构造函数
        //——————————&&表示右值引用,在函数中也是按照左值对待——————————//
        virtual ~A() {if(_p){delete [] _p,_p=nullptr;}}
    public:
        //"[]"重载
        int & operator[](int i);
        const int & operator[](int i)const;
        void display()
        {
            for(int i=0;i<this->_n;i++)
                std::cout<<this->_p[i]<<" ";
            std::cout<<std::endl;
        }
        int* check()
        {
            return _p;
        }
    private:   
        int _n, *_p;
};
//右值引用拷贝构造函数的实现
A::A(A && that)
{
    //nullptr:c++11预定义的空指针类型nullptr_t的常对象
    //nullptr这个指针类型可隐式转换为任意指针类型和bool类型,但不能转换为整数类型,以取代NULL
    //修改that._n的值和that._p的指向,变为空指针
    _n = that._n,_p = that._p,that._n=0,that._p=nullptr;
    //*this = that;//此代码不会调用下面重载的赋值操作符函数
    //that在函数内部是左值,只能传递左值引用但是现在传递的是右值引用
    //*this=static_cast<A&&>(that);等价于*this=std::move(that);
    //但是可能会出错
}
//右值引用赋值构造函数的实现
A & A::operator=(A && that)
{
    if(_p){delete[]_p;}
    _n = that._n,_p = that._p;that._n=0;that._p=nullptr;
    return *this;
}
int & A::operator[](int i)
{
    return _p[i];
}
const int & A::operator[](int i)const
{
    return _p[i];
}
int main()
{
    A a(4);
    for(int i=0;i<4;i++)
        a[i]=i+1;
    std::cout<<"a.display"<<std::endl;
    a.display();
   
    //使用右值操作的构造函数需要将a转换为右值引用
    A b(static_cast<A &&>(a));//使用拷贝构造函数,将c的数据对象拷贝给d对象
    std::cout<<"b.display"<<std::endl;
    b.display();

    A c(4);
    for(int i=0;i<4;i++)
        c[i]=i+1;
    std::cout<<"c.display"<<std::endl;
    c.display();

    A d=static_cast<A &&>(c);//使用赋值构造函数,将c的数据对象赋值给d对象
    std::cout<<"d.display"<<std::endl;
    d.display();

    //使用右值操作的赋值构造函数需要将a转换为右值引用
    A e = static_cast<A &&>(a);
    //不会输出,因为使用右值引用,前面的A b(static_cast<A &&>(a));已经将a的所有权移交到b,现在的a没有内容
    e.display();
    return 0;
}

输出:

a.display
1 2 3 4
b.display
1 2 3 4
c.display
1 2 3 4
d.display
1 2 3 4
e.display

例3

考虑深拷贝和右值引用的移动构造两种情况

#include<iostream>
using namespace std;

class A{
    public:
        A():_n(0),_p(nullptr){}
        explicit A(int n):_n(n),_p(new int[n]){}
        A(int n,int *p):_n(n),_p(p){}

        //实现深拷贝的传递const,不需要修改引用数据对象的值
        A(const A & that);// 1
        //实现移动语义,需要传递右值,需要修改引用数据对象的值
        A(A && that);
        //实现深拷贝的赋值操作符重载,不需要修改引用数据对象的值
        A & operator=(const A & that);// 2
        //实现移动语义赋值操作符重载,需要修改引用数据对象的值
        A & operator=(A && that);
        virtual ~A(){if(_p){delete[] _p,_p=nullptr;}}
    public:
        int & operator[](int i);
        const int & operator[](int i)const;
        void display()
        {
            for(int i=0;i<this->_n;i++)
                std::cout<<this->_p[i]<<" ";
            std::cout<<std::endl;
        }
    private:
        int _n,*_p;

};
//拷贝构造函数的实现
A::A(const A & that)
{
    this->_n = that._n;
    this->_p = new int[this->_n];
    for(int i=0;i<this->_n;i++)
        this->_p[i] = that._p[i];
}
//普通赋值构造函数的实现
A & A::operator=(const A & that)
{
    this->_n = that._n;
    //如果当前指针存在先进行销毁
    if(_p)
        delete[] _p;
    _p = new int[_n];
    for(int i=0;i<_n;i++)
        _p[i] = that._p[i];
    //最后返回引用
    return *this;
}
//[]操作赋重载的实现
int & A::operator[](int i)
{
    return _p[i];
}
const int & A::operator[](int i)const
{
    return _p[i];
}
//右值引用拷贝构造函数实现
A::A(A && that)
{
    _n = that._n,_p = that._p,that._n=0,that._p=nullptr;
}
//右值引用赋值构造函数实现
A & A::operator=(A && that)
{
    if(_p){delete[]_p;}
    _n = that._n,_p = that._p;that._n=0;that._p=nullptr;
    return *this;
}
int main()
{
    A a(4);
    for(int i=0;i<4;i++)
        a[i] = i+1; 
    A b(a);//1 调用拷贝构造函数
    std::cout<<"b.display"<<std::endl;
    b.display();

    //这里还可以使用a进行赋值,因为b的拷贝是深拷贝,a的数据对象还存在
    A c = a;//2 调用普通赋值版本
    std::cout<<"c.display"<<std::endl;
    c.display();
    
    //static_cast<new_type>(expression)
    A d(static_cast<A &&>(a));//调用移动构造版本
    std::cout<<"d.display"<<std::endl;
    d.display();

    A e = static_cast<A && >(a);//调用移动赋值版本
    std::cout<<"e.display";
    //不会输出,因为使用右值引用,前面的A b(static_cast<A &&>(a));已经将a的所有权移交到b,现在的a没有内容
    e.display();
}

输出:

b.display
1 2 3 4
c.display
1 2 3 4
d.display
1 2 3 4
e.display

例4

左值引用实现移动构造

#include<iostream>
using namespace std;

class A{
    public:
        A():_n(0),_p(nullptr){}
        explicit A(int n):_n(n),_p(new int[n]){}
        A(int n,int *p):_n(n),_p(p){}

        //实现深拷贝的传递const,不需要修改引用数据对象的值
        A(const A & that);// 1   
        //实现移动语义,拿掉const即可修改引用数据对象的值
        A(A & that);
        //实现深拷贝的赋值操作符重载,不需要修改引用数据对象的值
        A & operator=(const A & that);// 2
        //实现移动语义赋值操作符重载,需要修改引用数据对象的值,去掉const即可
        A & operator=(A & that);
        virtual ~A(){if(_p){delete[] _p,_p=nullptr;}}
    public:
        int & operator[](int i);
        const int & operator[](int i)const;
        void display()
        {
            for(int i=0;i<this->_n;i++)
                std::cout<<this->_p[i]<<" ";
            std::cout<<std::endl;
        }
        
    private:
        int _n,*_p;

};
A::A(A & that)
{
    _n = that._n,_p = that._p,that._n=0,that._p=nullptr;
}
A::A(const A & that)
{
    this->_n = that._n;
    _p = new int[_n];   
    for(int i=0;i<_n;i++)
        _p[i] = that._p[i];
}
A & A::operator=(A & that)
{
    _n = that._n,_p = that._p,that._n=0,that._p=nullptr;
    return *this;
}
A & A::operator=(const A & that)
{
    this->_n = that._n;
    if(_p){delete[] _p;}
    _p = new int[_n];
    for(int i=0;i<_n;i++)
        _p[i] = that._p[i];
    return *this;
}
int main()
{
    A a1;//缺省构造
    const A a2;//缺省构造
    
    A a3(a1);//调用A::A(A&),移动拷贝构造
    A a4(a2);//调用A::A(const A &)深拷贝构造
    
    //对于非常量必须转型为常量才能进行深拷贝,比如我要用非常量a1进行深拷贝
    //const_cast可以取消或者设置const属性
    //下面这个目的就是将a1转换成const A类型
    //const_cast<new_type>(expression)
    A a5(const_cast<const A & >(a1));
     
    A a6,a7,a8;//缺省构造
    a6 = a1;//调用A::A operator=(A&)
    a7 = a2;//调用A::A operator=(const A&)
   
    a8 = const_cast<const A &>(a1);//将a1转型为常量,然后赋值给a8调用A::Aoperator=(const A &)

    return 0;
}

猜你喜欢

转载自blog.csdn.net/Li_haiyu/article/details/82150494