C++学习之七

1)移动构造函数和移动赋值运算符的使用案例,代码如下:

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<stdio.h>
#include<string>

using namespace std;

class B
{
    
    
public:
    B():b_(20) //无参构造函数
    {
    
    
        //cout << "b constructor" << endl;
    }
    B(const B& obj): b_(obj.b_)
    {
    
    
        //cout << "b copy constructor" << endl;
    }
    virtual ~B()
    {
    
     
        //cout << "b deconstructor---" << endl; 
    }
public:
    int b_;
};

class A
{
    
    
public:
    A():m_pb(new B()){
    
     cout << "a--- constructor" << endl; }
    A(const A& obj):m_pb(new B(*obj.m_pb)) //老师的正确写法
    {
    
    
        //m_pb = obj.m_pb; 自己写的,是错的
        cout << "class A copy constructor" << endl;
    }
    //如果加入移动构造函数,就不会调用copy构造函数了
    A(A&& obj)noexcept:m_pb(obj.m_pb) //参数中不能有const!!! noexcept位置不能错
    {
    
    
        obj.m_pb = nullptr; //打断原来的指针跟老对象的关系
        cout << "A&&--- move constructor---" << endl;
    }
    //拷贝赋值运算符
    A& operator=(const A& src)
    {
    
    
        if (this == &src)
        {
    
    
            return *this;
        }
        delete m_pb; 
        m_pb = new B(*src.m_pb);
        std::cout << "class A move_assgin operator " << endl;
        return *this;
    }
    virtual ~A()
    {
    
    
        delete m_pb;
        cout << "A--- deconstructor---" << endl;
    }
private:
    B* m_pb;
};

//定义一个全局函数
A getA()
{
    
    
    A a;
    return a; //因为返回值返回,生成临时对象;这时,如果有移动构造函数,优先调用;没有则调用拷贝构造函数;
}

int main()
{
    
    
    //测试B类
    //B* pb = new B();
    //pb->b_ = 19;
    //B* pb2 = new B(*pb); //调用拷贝构造函数
    //delete pb; //没有这句话,就不会调用析构函数
    //delete pb2;

    //A a = getA();
    //A a1(a); //调用拷贝构造函数,因为a是左值
    //A a2(std::move(a));
    //A&& a3(std::move(a)); //没有影响,相当于给a起个别名a3

    //A a4 = getA();
    //A a2;
    //a2 = std::move(a4);//移动赋值运算符演示

    return 0;
}

2)左值引用与右值引用的学习,谁不会都可以问,保证给你讲明白

一)引用的学习:
1const的引用就可以绑定到右值;const int& a = 10;  //这样是可以的
     系统做了两件事情,等价于两条语句: int tmp = 10; (先定义一个临时变量)const int& a = tmp; 把临时变量绑定到引用;
2)右值引用,就是绑定右值;
     作用:用来绑定一些即将销毁或者一些临时对象上;
3)左值引用绑左值,右值引用绑右值;
    int a = 10; //const的引用既可以绑定左值,又可以绑定右值,左右通吃;
    const int& b = a;   //绑定左值
    const int& c = 10; //绑定右值
    int&& aa = 20; //虽然aa是右值引用,但本身是左值,所以,int& bb = aa;这条语句是合法的;

    前置递增递减运算符为左值:
    int i = 100;
    ++i = 200;
    cout << i << endl;
    后置递增递减运算符(如i++)为右值:因为i++先产生一个临时变量tmp;用完i后,i++;返回的是临时变量tmp;    
    int main() //i++测试代码
    {
    
    
        int i = 10;
        int&& b = i++; //绑定的是右值,没有绑定i,所以b的值和i没有任何关系!!!
        cout << b << endl; //10
        b = 40;
        cout << b << endl; //40
        cout << i << endl; //11

        return 0;
    }
4)任何函数的形参都是左值;
5)右值引用的引入目的:
     就是为了提高程序的运行效率;
6)std::move 根本没有移动的操作,就一个目的:把左值转换为右值;这样:以前定义的左值和右值引用就穿一条裤子了;
    int main()
    {
    
    
        int a = 10;
        cout << a << endl; //10 
        //下面这条语句,相当于b和a是一个变量了(b是a的别名);
        int&& b = std::move(a); //int&& b = a; 这样写就不可以
        a = 30;
        cout << b << endl; //40
        cout << a << endl; //40 

        return 0;
    }

    string st = "ABC";
    string def = std::move(st); //执行的是string的移动构造函数,没有执行std::move函数,相当于创建一个对象;
    string&& def = std::move(st); //执行了std::move函数;def和st穿一条裤子;

一)临时对象的学习:
 1) 三种情况产生临时对象:
a)(传值方式)函数参数传递;可以看出来产生了临时对象
b)  类型转换生成的临时对象;看不出来产生了临时对象;
   测试如:class Test{
    
    public: int x = 20};      Time test; test = 1000; 
   //test = 1000;  干了三个事:
    1)用1000数字创建了一个临时对象;
    2)调用拷贝赋值运算符,把这个临时对象的各个成员值赋给test对象;
    3)销毁这个临时创建的Test对象;
    改进:Time test = 1000; //定义时初始化,这个概念必须记住!!!
    C++语言只会为const引用(如:const string& rsource)产生临时变量;
c)函数返回临时对象
    解决办法:直接返回临时对象, return Test(ts.bal*2);
 2)类外运算符重载;

猜你喜欢

转载自blog.csdn.net/qq_30143193/article/details/132366261
今日推荐